r14168 by fschmid - Added the ability to stroke lines with patterns.

scribus-commit scribus-commit at lists.scribus.net
Sun Oct 18 13:06:40 CEST 2009


Revision: 14168
Author: fschmid
Date: 2009-10-18T08:55:03.615925Z
Commit message: Added the ability to stroke lines with patterns.

Changeset: 
M  /trunk/Scribus/scribus/scpainter.cpp
M  /trunk/Scribus/scribus/ui/propertiespalette.cpp
M  /trunk/Scribus/scribus/pageitem.cpp
M  /trunk/Scribus/scribus/scribusXml.cpp
M  /trunk/Scribus/scribus/scpainter.h
M  /trunk/Scribus/scribus/scribusdoc.cpp
M  /trunk/Scribus/scribus/pageitem.h
M  /trunk/Scribus/scribus/pageitem_line.cpp
M  /trunk/Scribus/scribus/plugins/fileloader/scribus12format/scribus12format.cpp
M  /trunk/Scribus/scribus/ui/colorpalette.ui
M  /trunk/Scribus/scribus/scribusdoc.h
M  /trunk/Scribus/scribus/plugins/fileloader/scribus13format/scribus13format.cpp
M  /trunk/Scribus/scribus/pageitem_polyline.cpp
M  /trunk/Scribus/scribus/pdflib_core.cpp
M  /trunk/Scribus/scribus/plugins/fileloader/scribus150format/scribus150format.cpp
M  /trunk/Scribus/scribus/pslib.cpp
M  /trunk/Scribus/scribus/pageitem_pathtext.cpp
M  /trunk/Scribus/scribus/pdflib_core.h
M  /trunk/Scribus/scribus/plugins/fileloader/scribus134format/scribus134format.cpp
M  /trunk/Scribus/scribus/ui/cpalette.cpp
M  /trunk/Scribus/scribus/pslib.h
M  /trunk/Scribus/scribus/plugins/fileloader/oodraw/oodrawimp.cpp
M  /trunk/Scribus/scribus/ui/cpalette.h
M  /trunk/Scribus/scribus/pageitem_desaxe.cpp
M  /trunk/Scribus/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp

Diffs:
Index: scribus/pdflib_core.cpp
===================================================================
--- scribus/pdflib_core.cpp	(revision 14167)
+++ scribus/pdflib_core.cpp	(revision 14168)
@@ -2034,13 +2034,19 @@
 							PutPage(tmpOut);
 						}
 						PutPage("Q\n");
-						if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty())) && (!ite->isTableItem))
+						if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty())) && (!ite->isTableItem))
 						{
 							if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 								PutPage(PDF_TransparenzStroke(ite));
-							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
+							if (ite->NamedLStyle.isEmpty())
 							{
 								PutPage(SetClipPath(ite));
+								if (!ite->strokePattern().isEmpty())
+								{
+									if (!PDF_StrokePattern(tmpOut, ite))
+										return false;
+									PutPage(tmpOut);
+								}
 								PutPage("h\nS\n");
 							}
 							else
@@ -2067,6 +2073,12 @@
 						{
 							PutPage("0 0 m\n");
 							PutPage(FToStr(ite->width())+" 0 l\n");
+							if (!ite->strokePattern().isEmpty())
+							{
+								if (!PDF_StrokePattern(tmpOut, ite))
+									return false;
+								PutPage(tmpOut);
+							}
 							PutPage("S\n");
 						}
 						else
@@ -2114,13 +2126,19 @@
 								PutPage("h\nf*\n");
 							}
 						}
-						if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+						if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 						{
 							if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 								PutPage(PDF_TransparenzStroke(ite));
 							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 							{
 								PutPage(SetClipPath(ite));
+								if (!ite->strokePattern().isEmpty())
+								{
+									if (!PDF_StrokePattern(tmpOut, ite))
+										return false;
+									PutPage(tmpOut);
+								}
 								PutPage("h\nS\n");
 							}
 							else
@@ -2158,13 +2176,19 @@
 								}
 							}
 						}
-						if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+						if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 						{
 							if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 								PutPage(PDF_TransparenzStroke(ite));
-							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
+							if (ite->NamedLStyle.isEmpty())
 							{
 								PutPage(SetClipPath(ite, false));
+								if (!ite->strokePattern().isEmpty())
+								{
+									if (!PDF_StrokePattern(tmpOut, ite))
+										return false;
+									PutPage(tmpOut);
+								}
 								PutPage("S\n");
 							}
 							else
@@ -2222,13 +2246,19 @@
 							if (ite->PoLine.size() > 3)
 							{
 								PutPage("q\n");
-								if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+								if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 								{
 									if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 										PutPage(PDF_TransparenzStroke(ite));
-									if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
+									if (ite->NamedLStyle.isEmpty())
 									{
 										PutPage(SetClipPath(ite, false));
+										if (!ite->strokePattern().isEmpty())
+										{
+											if (!PDF_StrokePattern(tmpOut, ite))
+												return false;
+											PutPage(tmpOut);
+										}
 										PutPage("S\n");
 									}
 									else
@@ -3435,17 +3465,25 @@
 				tmp += tmpOut;
 			}
 			tmp += "Q\n";
-			if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty())) && (!ite->isTableItem))
+			if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty())) && (!ite->isTableItem))
 			{
 				if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4) ))
 					tmp += PDF_TransparenzStroke(ite);
 				if (ite->NamedLStyle.isEmpty()) //&& (ite->lineWidth() != 0.0))
 				{
-					if (ite->lineColor() != CommonStrings::None)
+					if (!ite->strokePattern().isEmpty())
 					{
 						tmp += SetClipPath(ite);
+						if (!PDF_StrokePattern(tmpOut, ite))
+							return false;
+						tmp += tmpOut;
 						tmp += "h\nS\n";
 					}
+					else if (ite->lineColor() != CommonStrings::None)
+					{
+						tmp += SetClipPath(ite);
+						tmp += "h\nS\n";
+					}
 				}
 				else
 				{
@@ -3494,17 +3532,25 @@
 				tmp += "1 0 0 -1 0 "+FToStr(-ite->height())+" cm\n";
 			tmp += setTextSt(ite, PNr, pag);
 			tmp += "Q\n";
-			if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty())) && (!ite->isTableItem))
+			if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty())) && (!ite->isTableItem))
 			{
 				if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4) ))
 					tmp += PDF_TransparenzStroke(ite);
 				if (ite->NamedLStyle.isEmpty()) //&& (ite->lineWidth() != 0.0))
 				{
-					if (ite->lineColor() != CommonStrings::None)
+					if (!ite->strokePattern().isEmpty())
 					{
 						tmp += SetClipPath(ite);
+						if (!PDF_StrokePattern(tmpOut, ite))
+							return false;
+						tmp += tmpOut;
 						tmp += "h\nS\n";
 					}
+					else if (ite->lineColor() != CommonStrings::None)
+					{
+						tmp += SetClipPath(ite);
+						tmp += "h\nS\n";
+					}
 				}
 				else
 				{
@@ -3526,12 +3572,21 @@
 				tmp += PDF_TransparenzStroke(ite);
 			if (ite->NamedLStyle.isEmpty())
 			{
-				if (ite->lineColor() != CommonStrings::None)
+				if (!ite->strokePattern().isEmpty())
 				{
+					if (!PDF_StrokePattern(tmpOut, ite))
+						return false;
+					tmp += tmpOut;
 					tmp += "0 0 m\n";
 					tmp += FToStr(ite->width())+" 0 l\n";
 					tmp += "S\n";
 				}
+				else if (ite->lineColor() != CommonStrings::None)
+				{
+					tmp += "0 0 m\n";
+					tmp += FToStr(ite->width())+" 0 l\n";
+					tmp += "S\n";
+				}
 			}
 			else
 			{
@@ -3582,17 +3637,25 @@
 						tmp += "h\nf\n";
 				}
 			}
-			if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+			if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 			{
 				if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 					tmp += PDF_TransparenzStroke(ite);
 				if (ite->NamedLStyle.isEmpty()) //&& (ite->lineWidth() != 0.0))
 				{
-					if (ite->lineColor() != CommonStrings::None)
+					if (!ite->strokePattern().isEmpty())
 					{
 						tmp += SetClipPath(ite);
+						if (!PDF_StrokePattern(tmpOut, ite))
+							return false;
+						tmp += tmpOut;
 						tmp += "h\nS\n";
 					}
+					else if (ite->lineColor() != CommonStrings::None)
+					{
+						tmp += SetClipPath(ite);
+						tmp += "h\nS\n";
+					}
 				}
 				else
 				{
@@ -3629,17 +3692,25 @@
 					}
 				}
 			}
-			if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+			if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 			{
 				if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 					tmp += PDF_TransparenzStroke(ite);
 				if (ite->NamedLStyle.isEmpty()) //&& (ite->lineWidth() != 0.0))
 				{
-					if (ite->lineColor() != CommonStrings::None)
+					if (!ite->strokePattern().isEmpty())
 					{
 						tmp += SetClipPath(ite, false);
+						if (!PDF_StrokePattern(tmpOut, ite))
+							return false;
+						tmp += tmpOut;
 						tmp += "S\n";
 					}
+					else if (ite->lineColor() != CommonStrings::None)
+					{
+						tmp += SetClipPath(ite, false);
+						tmp += "S\n";
+					}
 				}
 				else
 				{
@@ -3696,13 +3767,21 @@
 				if (ite->PoLine.size() > 3)
 				{
 					tmp += "q\n";
-					if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
+					if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()))
 					{
 						if (((ite->lineTransparency() != 0) || (ite->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
 							tmp += PDF_TransparenzStroke(ite);
 						if (ite->NamedLStyle.isEmpty()) //&& (ite->lineWidth() != 0.0))
 						{
-							if (ite->lineColor() != CommonStrings::None)
+						if (!ite->strokePattern().isEmpty())
+						{
+							tmp += SetClipPath(ite, false);
+							if (!PDF_StrokePattern(tmpOut, ite))
+								return false;
+							tmp += tmpOut;
+								tmp += "S\n";
+							}
+							else if (ite->lineColor() != CommonStrings::None)
 							{
 								tmp += SetClipPath(ite, false);
 								tmp += "S\n";
@@ -3766,8 +3845,16 @@
 	}
 	if (ite->NamedLStyle.isEmpty())
 	{
-		if (ite->lineColor() != CommonStrings::None)
+		if (!ite->strokePattern().isEmpty())
 		{
+			tmp += SetClipPathArray(&arrow);
+			QString tmpOut;
+			PDF_StrokePattern(tmpOut, ite, true);
+			tmp += tmpOut;
+			tmp += "h\nf*\n";
+		}
+		else if (ite->lineColor() != CommonStrings::None)
+		{
 			tmp += putColor(ite->lineColor(), ite->lineShade(), true);
 			tmp += SetClipPathArray(&arrow);
 			tmp += "h\nf*\n";
@@ -5188,6 +5275,245 @@
 	return tmp;
 }
 
+bool PDFLibCore::PDF_StrokePattern(QString& output, PageItem *currItem, bool forArrow)
+{
+	QStack<PageItem*> groupStack;
+	QString tmp2 = "", tmpOut;
+	ScPattern *pat = &doc.docPatterns[currItem->strokePattern()];
+	for (int em = 0; em < pat->items.count(); ++em)
+	{
+		PageItem* item = pat->items.at(em);
+		if (item->isGroupControl)
+		{
+			tmp2 += "q\n";
+			FPointArray cl = item->PoLine.copy();
+			FPointArray clb = item->PoLine.copy();
+			QTransform mm;
+			mm.translate(item->gXpos, item->gYpos - pat->height);
+			mm.rotate(item->rotation());
+			cl.map( mm );
+			item->PoLine = cl;
+			tmp2 += SetClipPath(item);
+			tmp2 += "h W* n\n";
+			groupStack.push(item->groupsLastItem);
+			item->PoLine = clb.copy();
+			continue;
+		}
+		tmp2 += "q\n";
+		tmp2 +=  "1 0 0 1 "+FToStr(item->gXpos)+" "+FToStr(-(item->gYpos - pat->height))+" cm\n";
+		item->setXYPos(item->xPos() + ActPageP->xOffset(), item->yPos() + ActPageP->yOffset(), true);
+		inPattern++;
+		if (!PDF_ProcessItem(tmpOut, item, doc.Pages->at(0), 0, true, true))
+			return false;
+		tmp2 += tmpOut;
+		item->setXYPos(item->xPos() - ActPageP->xOffset(), item->yPos() - ActPageP->yOffset(), true);
+		inPattern--;
+		tmp2 += "Q\n";
+		if (groupStack.count() != 0)
+		{
+			while (item == groupStack.top())
+			{
+				tmp2 += "Q\n";
+				groupStack.pop();
+				if (groupStack.count() == 0)
+					break;
+			}
+		}
+	}
+	for (int em = 0; em < pat->items.count(); ++em)
+	{
+		PageItem* item = pat->items.at(em);
+		if (!item->isTableItem)
+			continue;
+		if ((item->lineColor() == CommonStrings::None) || (item->lineWidth() == 0.0))
+			continue;
+		tmp2 += "q\n";
+		if ((item->doOverprint) && (!Options.UseRGB))
+		{
+			QString ShName = ResNam+QString::number(ResCount);
+			ResCount++;
+			Transpar[ShName] = writeGState("/OP true\n"
+										"/op true\n"
+										"/OPM 1\n");
+			tmp2 += "/"+ShName+" gs\n";
+		}
+		if (((item->lineTransparency() != 0) || (item->lineBlendmode() != 0)) && ((Options.Version >= PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_X4)))
+			tmp2 += PDF_TransparenzStroke(item);
+		if (item->lineColor() != CommonStrings::None)
+			tmp2 += putColor(item->lineColor(), item->lineShade(), false);
+		tmp2 += FToStr(fabs(item->lineWidth()))+" w\n";
+		if (item->DashValues.count() != 0)
+		{
+			tmp2 += "[ ";
+			QVector<double>::iterator it;
+			for ( it = item->DashValues.begin(); it != item->DashValues.end(); ++it )
+			{
+				int da = static_cast<int>(*it);
+				if (da != 0)
+					tmp2 += QString::number(da)+" ";
+			}
+			tmp2 += "] "+QString::number(static_cast<int>(item->DashOffset))+" d\n";
+		}
+		else
+			tmp2 += "["+getDashString(item->PLineArt, item->lineWidth())+"] 0 d\n";
+		tmp2 += "2 J\n";
+		switch (item->PLineJoin)
+		{
+			case Qt::MiterJoin:
+				tmp2 += "0 j\n";
+				break;
+			case Qt::BevelJoin:
+				tmp2 += "2 j\n";
+				break;
+			case Qt::RoundJoin:
+				tmp2 += "1 j\n";
+				break;
+			default:
+				tmp2 += "0 j\n";
+				break;
+		}
+		tmp2 +=  "1 0 0 1 "+FToStr(item->gXpos)+" "+FToStr(-(item->gYpos - pat->height))+" cm\n";
+		if (item->rotation() != 0)
+		{
+			double sr = sin(-item->rotation()* M_PI / 180.0);
+			double cr = cos(-item->rotation()* M_PI / 180.0);
+			if ((cr * cr) < 0.000001)
+				cr = 0;
+			if ((sr * sr) < 0.000001)
+				sr = 0;
+			tmp2 += FToStr(cr)+" "+FToStr(sr)+" "+FToStr(-sr)+" "+FToStr(cr)+ " 0 0 cm\n";
+		}
+		if ((item->TopLine) || (item->RightLine) || (item->BottomLine) || (item->LeftLine))
+		{
+			if (item->TopLine)
+			{
+				tmp2 += "0 0 m\n";
+				tmp2 += FToStr(item->width())+" 0 l\n";
+			}
+			if (item->RightLine)
+			{
+				tmp2 += FToStr(item->width())+" 0 m\n";
+				tmp2 += FToStr(item->width())+" "+FToStr(-item->height())+" l\n";
+			}
+			if (item->BottomLine)
+			{
+				tmp2 += "0 "+FToStr(-item->height())+" m\n";
+				tmp2 += FToStr(item->width())+" "+FToStr(-item->height())+" l\n";
+			}
+			if (item->LeftLine)
+			{
+				tmp2 += "0 0 m\n";
+				tmp2 += "0 "+FToStr(-item->height())+" l\n";
+			}
+			tmp2 += "S\n";
+		}
+		tmp2 += "Q\n";
+	}
+	if (Options.Compress)
+		tmp2 = CompressStr(&tmp2);
+	uint patObject = newObject();
+	StartObj(patObject);
+	PutDoc("<< /Type /Pattern\n");
+	PutDoc("/PatternType 1\n");
+	PutDoc("/PaintType 1\n");
+	PutDoc("/TilingType 1\n");
+	PutDoc("/BBox [ 0 0 "+FToStr(pat->width)+" "+FToStr(pat->height)+" ]\n");
+	QTransform mpa;
+	if (inPattern == 0)
+	{
+		mpa.translate(currItem->xPos() - ActPageP->xOffset(), ActPageP->height() - (currItem->yPos() - ActPageP->yOffset()));
+		mpa.rotate(-currItem->rotation());
+	}
+	double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+	currItem->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+	mpa.translate(-currItem->lineWidth() / 2.0, currItem->lineWidth() / 2.0);
+	mpa.translate(patternOffsetX, -patternOffsetY);
+	mpa.rotate(-patternRotation);
+	mpa.scale(pat->scaleX, pat->scaleY);
+	mpa.scale(patternScaleX / 100.0 , patternScaleY / 100.0);
+	PutDoc("/Matrix ["+FToStr(mpa.m11())+" "+FToStr(mpa.m12())+" "+FToStr(mpa.m21())+" "+FToStr(mpa.m22())+" "+FToStr(mpa.dx())+" "+FToStr(mpa.dy())+"]\n");
+	PutDoc("/XStep "+FToStr(pat->width)+"\n");
+	PutDoc("/YStep "+FToStr(pat->height)+"\n");
+	PutDoc("/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n");
+	if (Seite.ImgObjects.count() != 0)
+	{
+		PutDoc("/XObject <<\n");
+		QMap<QString,int>::Iterator it;
+		for (it = Seite.ImgObjects.begin(); it != Seite.ImgObjects.end(); ++it)
+			PutDoc("/"+it.key()+" "+QString::number(it.value())+" 0 R\n");
+		PutDoc(">>\n");
+	}
+	if (Seite.FObjects.count() != 0)
+	{
+		PutDoc("/Font << \n");
+		QMap<QString,int>::Iterator it2;
+		for (it2 = Seite.FObjects.begin(); it2 != Seite.FObjects.end(); ++it2)
+			PutDoc("/"+it2.key()+" "+QString::number(it2.value())+" 0 R\n");
+		PutDoc(">>\n");
+	}
+	if (Shadings.count() != 0)
+	{
+		PutDoc("/Shading << \n");
+		QMap<QString,int>::Iterator it3;
+		for (it3 = Shadings.begin(); it3 != Shadings.end(); ++it3)
+			PutDoc("/"+it3.key()+" "+QString::number(it3.value())+" 0 R\n");
+		PutDoc(">>\n");
+	}
+	if (Patterns.count() != 0)
+	{
+		PutDoc("/Pattern << \n");
+		QMap<QString,int>::Iterator it3p;
+		for (it3p = Patterns.begin(); it3p != Patterns.end(); ++it3p)
+			PutDoc("/"+it3p.key()+" "+QString::number(it3p.value())+" 0 R\n");
+		PutDoc(">>\n");
+	}
+	if (Transpar.count() != 0)
+	{
+		PutDoc("/ExtGState << \n");
+		QMap<QString,int>::Iterator it3t;
+		for (it3t = Transpar.begin(); it3t != Transpar.end(); ++it3t)
+			PutDoc("/"+it3t.key()+" "+QString::number(it3t.value())+" 0 R\n");
+		PutDoc(">>\n");
+	}
+	if ((ICCProfiles.count() != 0) || (spotMap.count() != 0))
+	{
+		PutDoc("/ColorSpace << \n");
+		QMap<QString,ICCD>::Iterator it3c;
+		if (ICCProfiles.count() != 0)
+		{
+			for (it3c = ICCProfiles.begin(); it3c != ICCProfiles.end(); ++it3c)
+				PutDoc("/"+it3c.value().ResName+" "+QString::number(it3c.value().ResNum)+" 0 R\n");
+		}
+		QMap<QString,SpotC>::Iterator it3sc;
+		if (spotMap.count() != 0)
+		{
+			for (it3sc = spotMap.begin(); it3sc != spotMap.end(); ++it3sc)
+				PutDoc("/"+it3sc.value().ResName+" "+QString::number(it3sc.value().ResNum)+" 0 R\n");
+		}
+		PutDoc(">>\n");
+	}
+	PutDoc(">>\n");
+	PutDoc("/Length "+QString::number(tmp2.length()));
+	if (Options.Compress)
+		PutDoc("\n/Filter /FlateDecode");
+	PutDoc(" >>\nstream\n"+EncStream(tmp2, patObject)+"\nendstream\nendobj\n");
+	Patterns.insert("Pattern"+QString::number(patObject), patObject);
+	QString tmp;
+	if (forArrow)
+	{
+		tmp = "/Pattern cs\n";
+		tmp += "/Pattern"+QString::number(patObject)+" scn\n";
+	}
+	else
+	{
+		tmp = "/Pattern CS\n";
+		tmp += "/Pattern"+QString::number(patObject)+" SCN\n";
+	}
+	ResCount++;
+	output = tmp;
+	return true;
+}
+
 bool PDFLibCore::PDF_Gradient(QString& output, PageItem *currItem)
 {
 	if (currItem->GrType == 8)
Index: scribus/pslib.h
===================================================================
--- scribus/pslib.h	(revision 14167)
+++ scribus/pslib.h	(revision 14168)
@@ -131,6 +131,7 @@
 		virtual void GetBleeds(Page* page, double& left, double& right);
 		virtual void GetBleeds(Page* page, double& left, double& right, double& bottom, double& top);
 		virtual void SetClipPath(FPointArray *c, bool poly = true);
+		virtual void HandleStrokePattern(PageItem *c);
 		virtual void HandleGradient(PageItem *c, double w, double h, bool gcr);
 		virtual void SetColor(const QString& color, double shade, int *h, int *s, int *v, int *k, bool gcr);
 		virtual void SetColor(const ScColor& color, double shade, int *h, int *s, int *v, int *k, bool gcr);
Index: scribus/pageitem_line.cpp
===================================================================
--- scribus/pageitem_line.cpp	(revision 14167)
+++ scribus/pageitem_line.cpp	(revision 14168)
@@ -58,11 +58,21 @@
 		{
 			if (NamedLStyle.isEmpty())
 			{
-				if (lineColor() != CommonStrings::None)
+				if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal)))
+				{
+					p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation);
+					p->setStrokeMode(ScPainter::Pattern);
 					p->drawLine(FPoint(0, 0), FPoint(Width, 0));
+				}
+				else if (lineColor() != CommonStrings::None)
+				{
+					p->setStrokeMode(ScPainter::Solid);
+					p->drawLine(FPoint(0, 0), FPoint(Width, 0));
+				}
 			}
 			else
 			{
+				p->setStrokeMode(ScPainter::Solid);
 				multiLine ml = m_Doc->MLineStyles[NamedLStyle];
 				QColor tmp;
 				for (int it = ml.size()-1; it > -1; it--)
Index: scribus/pdflib_core.h
===================================================================
--- scribus/pdflib_core.h	(revision 14167)
+++ scribus/pdflib_core.h	(revision 14168)
@@ -151,6 +151,7 @@
 	QString PDF_ProcessTableItem(PageItem* ite, const Page* pag);
 	QString drawArrow(PageItem *ite, QTransform &arrowTrans, int arrowIndex);
 	void    PDF_Bookmark(PageItem *currItem, double ypos);
+	bool    PDF_StrokePattern(QString& output, PageItem *currItem, bool forArrow = false);
 	bool    PDF_Gradient(QString& output, PageItem *currItem);
 	QString PDF_DoLinGradient(PageItem *currItem, QList<double> Stops, QList<double> Trans, const QStringList& Colors, QStringList colorNames, QList<int> colorShades);
 	QString PDF_TransparenzFill(PageItem *currItem);
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp	(revision 14167)
+++ scribus/scribusdoc.cpp	(revision 14168)
@@ -2775,16 +2775,22 @@
 	{
 		if ((!results.contains(MasterItems.at(c)->pattern())) && (MasterItems.at(c)->GrType == 8))
 			results.append(MasterItems.at(c)->pattern());
+		if (!results.contains(MasterItems.at(c)->strokePattern()))
+			results.append(MasterItems.at(c)->strokePattern());
 	}
 	for (int c = 0; c < DocItems.count(); ++c)
 	{
 		if ((!results.contains(DocItems.at(c)->pattern())) && (DocItems.at(c)->GrType == 8))
 			results.append(DocItems.at(c)->pattern());
+		if (!results.contains(DocItems.at(c)->strokePattern()))
+			results.append(DocItems.at(c)->strokePattern());
 	}
 	for (int c = 0; c < FrameItems.count(); ++c)
 	{
 		if ((!results.contains(FrameItems.at(c)->pattern())) && (FrameItems.at(c)->GrType == 8))
 			results.append(FrameItems.at(c)->pattern());
+		if (!results.contains(FrameItems.at(c)->strokePattern()))
+			results.append(FrameItems.at(c)->strokePattern());
 	}
 	for (int c = 0; c < results.count(); ++c)
 	{
@@ -2811,6 +2817,9 @@
 				if (!pat.isEmpty() && !results.contains(pat))
 					results.append(currItem->pattern());
 			}
+			const QString& pat2 = currItem->strokePattern();
+			if (!pat2.isEmpty() && !results.contains(pat2))
+				results.append(currItem->strokePattern());
 		}
 		for (int c = 0; c < results.count(); ++c)
 		{
@@ -2838,6 +2847,9 @@
 			if (!patName.isEmpty() && !results.contains(patName))
 				pats.append(patName);
 		}
+		const QString& pat2 = pat->items.at(c)->strokePattern();
+		if (!pat2.isEmpty() && !results.contains(pat2))
+			results.append(pat->items.at(c)->strokePattern());
 	}
 	if (!pats.isEmpty())
 	{
@@ -5826,6 +5838,42 @@
 	}
 }
 
+void ScribusDoc::itemSelection_SetItemStrokePattern(QString pattern)
+{
+	uint selectedItemCount=m_Selection->count();
+	if (selectedItemCount != 0)
+	{
+		m_updateManager.setUpdatesDisabled();
+		PageItem *currItem;
+		for (uint a = 0; a < selectedItemCount; ++a)
+		{
+			currItem = m_Selection->itemAt(a);
+			currItem->setStrokePattern(pattern);
+			currItem->update();
+		}
+		m_updateManager.setUpdatesEnabled();
+		changed();
+	}
+}
+
+void ScribusDoc::itemSelection_SetItemStrokePatternProps(double imageScaleX, double imageScaleY, double offsetX, double offsetY, double rotation)
+{
+	uint selectedItemCount=m_Selection->count();
+	if (selectedItemCount != 0)
+	{
+		m_updateManager.setUpdatesDisabled();
+		PageItem *currItem;
+		for (uint a = 0; a < selectedItemCount; ++a)
+		{
+			currItem = m_Selection->itemAt(a);
+			currItem->setStrokePatternTransform(imageScaleX, imageScaleY, offsetX, offsetY, rotation);
+			currItem->update();
+		}
+		m_updateManager.setUpdatesEnabled();
+		changed();
+	}
+}
+
 void ScribusDoc::itemSelection_SetEffects(int s, Selection* customSelection)
 {
 	CharStyle newStyle;
@@ -7585,6 +7633,18 @@
 	uint selectedItemCount=itemSelection->count();
 	if (selectedItemCount == 0)
 		return;
+	m_updateManager.setUpdatesDisabled();
+	for (uint i = 0; i < selectedItemCount; ++i)
+	{
+		PageItem *currItem;
+		currItem = itemSelection->itemAt(i);
+		currItem->stroke_gradient = newGradient;
+		currItem->update();
+	}
+	/*if (selectedItemCount>1)
+		regionsChanged()->update(QRectF());*/
+	m_updateManager.setUpdatesEnabled();
+	changed();
 //Teaser for jghali
 }
 
Index: scribus/pageitem_polyline.cpp
===================================================================
--- scribus/pageitem_polyline.cpp	(revision 14167)
+++ scribus/pageitem_polyline.cpp	(revision 14168)
@@ -94,11 +94,21 @@
 			p->setupPolygon(&PoLine, false);
 			if (NamedLStyle.isEmpty())
 			{
-				if (lineColor() != CommonStrings::None)
+				if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal)))
+				{
+					p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation);
+					p->setStrokeMode(ScPainter::Pattern);
 					p->strokePath();
+				}
+				else if (lineColor() != CommonStrings::None)
+				{
+					p->setStrokeMode(ScPainter::Solid);
+					p->strokePath();
+				}
 			}
 			else
 			{
+				p->setStrokeMode(ScPainter::Solid);
 				multiLine ml = m_Doc->MLineStyles[NamedLStyle];
 				QColor tmp;
 				for (int it = ml.size()-1; it > -1; it--)
Index: scribus/scribusXml.cpp
===================================================================
--- scribus/scribusXml.cpp	(revision 14167)
+++ scribus/scribusXml.cpp	(revision 14168)
@@ -1207,6 +1207,12 @@
 	QString modelFile;
 	QString currentView;
 	QString gradName;
+	QString StrokePattern;
+	double patternScaleXS;
+	double patternScaleYS;
+	double patternOffsetXS;
+	double patternOffsetYS;
+	double patternRotationS;
 	while(!sReader.atEnd() && !sReader.hasError())
 	{
 		sReader.readNext();
@@ -1284,6 +1290,12 @@
 			LatexConfig = attrAsString(attrs, "LatexConfig", "");
 			modelFile = attrAsString(attrs, "modelFile", "");
 			currentView = attrAsString(attrs, "currentViewName", "");
+			StrokePattern = attrAsString(attrs, "patternS", "");
+			patternScaleXS   = attrAsDbl(attrs, "pScaleXS", 100.0);
+			patternScaleYS   = attrAsDbl(attrs, "pScaleYS", 100.0);
+			patternOffsetXS  = attrAsDbl(attrs, "pOffsetXS", 0.0);
+			patternOffsetYS  = attrAsDbl(attrs, "pOffsetYS", 0.0);
+			patternRotationS = attrAsDbl(attrs, "pRotationS", 0.0);
 		}
 		if (inItem && sReader.isStartElement() && tagName == "ITEXT")
 		{
@@ -1435,6 +1447,8 @@
 			PageItem* Neu = doc->Items->at(doc->Items->count()-1);
 			Neu->setGradient(gradName);
 			Neu->doOverprint = doOverprint;
+			Neu->setStrokePattern(StrokePattern);
+			Neu->setStrokePatternTransform(patternScaleXS, patternScaleYS, patternOffsetXS, patternOffsetYS, patternRotationS);
 			storyText.setDefaultStyle(Neu->itemText.defaultStyle());
 			if (Neu->asLatexFrame())
 			{
@@ -2275,7 +2289,6 @@
 		writer.writeAttribute("GRSTARTY", item->GrStartY);
 		writer.writeAttribute("GRENDX"  , item->GrEndX);
 		writer.writeAttribute("GRENDY"  , item->GrEndY);
-		writer.writeAttribute("GRNAME"  , item->gradient());
 	}
 
 	if (item->effectsInUse.count() != 0)
@@ -2331,23 +2344,34 @@
 		}
 		else
 		{
-			QList<VColorStop*> cstops = item->fill_gradient.colorStops();
-			for (uint cst = 0; cst < item->fill_gradient.Stops(); ++cst)
+			if (item->gradient().isEmpty())
 			{
-				writer.writeStartElement("CSTOP");
-				writer.writeAttribute("RAMP" , cstops.at(cst)->rampPoint);
-				writer.writeAttribute("NAME" , cstops.at(cst)->name);
-				writer.writeAttribute("SHADE", cstops.at(cst)->shade);
-				writer.writeAttribute("TRANS", cstops.at(cst)->opacity);
-				writer.writeEndElement();
+				QList<VColorStop*> cstops = item->fill_gradient.colorStops();
+				for (uint cst = 0; cst < item->fill_gradient.Stops(); ++cst)
+				{
+					writer.writeStartElement("CSTOP");
+					writer.writeAttribute("RAMP" , cstops.at(cst)->rampPoint);
+					writer.writeAttribute("NAME" , cstops.at(cst)->name);
+					writer.writeAttribute("SHADE", cstops.at(cst)->shade);
+					writer.writeAttribute("TRANS", cstops.at(cst)->opacity);
+					writer.writeEndElement();
+				}
 			}
-			// must be writen before
-			// writer.writeAttribute("GRSTARTX", item->GrStartX);
-			// writer.writeAttribute("GRSTARTY", item->GrStartY);
-			// writer.writeAttribute("GRENDX"  , item->GrEndX);
-			// writer.writeAttribute("GRENDY"  , item->GrEndY);
+			else
+				writer.writeAttribute("GRNAME"  , item->gradient());
 		}
 	}
+	if (!item->strokePattern().isEmpty())
+	{
+		writer.writeAttribute("patternS", item->strokePattern());
+		double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+		item->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+		writer.writeAttribute("pScaleXS", patternScaleX);
+		writer.writeAttribute("pScaleYS", patternScaleY);
+		writer.writeAttribute("pOffsetXS", patternOffsetX);
+		writer.writeAttribute("pOffsetYS", patternOffsetY);
+		writer.writeAttribute("pRotationS", patternRotation);
+	}
 	if (item->asLatexFrame())
 	{
 		PageItem_LatexFrame *latexitem = item->asLatexFrame();
Index: scribus/pageitem_pathtext.cpp
===================================================================
--- scribus/pageitem_pathtext.cpp	(revision 14167)
+++ scribus/pageitem_pathtext.cpp	(revision 14168)
@@ -105,11 +105,21 @@
 			p->setupPolygon(&PoLine, false);
 			if (NamedLStyle.isEmpty())
 			{
-				if (lineColor() != CommonStrings::None)
+				if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal)))
+				{
+					p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation);
+					p->setStrokeMode(ScPainter::Pattern);
 					p->strokePath();
+				}
+				else if (lineColor() != CommonStrings::None)
+				{
+					p->setStrokeMode(ScPainter::Solid);
+					p->strokePath();
+				}
 			}
 			else
 			{
+				p->setStrokeMode(ScPainter::Solid);
 				multiLine ml = m_Doc->MLineStyles[NamedLStyle];
 				QColor tmp;
 				for (int it = ml.size()-1; it > -1; it--)
Index: scribus/pageitem.h
===================================================================
--- scribus/pageitem.h	(revision 14167)
+++ scribus/pageitem.h	(revision 14168)
@@ -595,6 +595,11 @@
 	void setGradientType(int val) { GrType = val; }
 	void gradientVector(double& startX, double& startY, double& endX, double& endY) const;
 	void setGradientVector(double startX, double startY, double endX, double endY);
+
+	int strokeGradientType() const { return GrTypeStroke; }
+	void setStrokeGradientType(int val) { GrTypeStroke = val; }
+	void strokeGradientVector(double& startX, double& startY, double& endX, double& endY) const;
+	void setStrokeGradientVector(double startX, double startY, double endX, double endY);
 	// 
 	bool fillEvenOdd() const { return fillRule; }
 	void setFillEvenOdd(bool val) { fillRule = val; }
@@ -676,6 +681,15 @@
 	 */
 	void setGradient(const QString &newGradient);
 
+	/** @brief Get the name of the stroke gradient of the object */
+	QString strokeGradient() const { return gradientStrokeVal; }
+
+	/**
+	 * @brief Set the stroke gradient of the object.
+	 * @param newGradient stroke gradient for the object
+	 */
+	void setStrokeGradient(const QString &newGradient);
+
 	/** @brief Get the name of the pattern of the object */
 	QString pattern() const { return patternVal; }
 
@@ -757,6 +771,23 @@
 	 */
 	void setLineTransparency(double newTransparency);
 
+	/** @brief Get the name of the stroke pattern of the object */
+	QString strokePattern() const { return patternStrokeVal; }
+
+	/** @brief Get the stroke pattern transformation matrix of the object */
+	void strokePatternTransform(double &scaleX, double &scaleY, double &offsetX, double &offsetY, double &rotation) const;
+
+	/**
+	 * @brief Set the stroke pattern of the object.
+	 * @param newPattern stroke pattern for the object
+	 */
+	void setStrokePattern(const QString &newPattern);
+	
+	/**
+	 * @brief Set the stroke pattern transformation of the object.
+	 */
+	void setStrokePatternTransform(double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
+
 	/** @brief Set the QColor for the line */
 	void setLineQColor();
 	/** @brief Set the QColor for the fill */
@@ -1303,6 +1334,37 @@
 	double m_lineWidth;
 	double Oldm_lineWidth;
 
+	/**
+	 * @brief Stroke pattern name
+	 * @sa PageItem::strokePattern(), PageItem::setStrokePattern()
+	 */
+	QString patternStrokeVal;
+	/**
+	 * @brief Stroke pattern transformation matrix
+	 */
+	double patternStrokeScaleX;
+	double patternStrokeScaleY;
+	double patternStrokeOffsetX;
+	double patternStrokeOffsetY;
+	double patternStrokeRotation;
+	
+
+	/**
+	 * @brief Stroke gradient name
+	 * @sa PageItem::strokeGradient(), PageItem::setStrokeGradient()
+	 */
+	QString gradientStrokeVal;
+	VGradient stroke_gradient;
+
+	/** 
+	* @brief Stroke gradient variables
+	*/
+	int GrTypeStroke;
+	double GrStrokeStartX;
+	double GrStrokeStartY;
+	double GrStrokeEndX;
+	double GrStrokeEndY;
+
 	/** Inline Image */
 	bool isInlineImage;
 	QTemporaryFile *tempImageFile;
Index: scribus/scpainter.cpp
===================================================================
--- scribus/scpainter.cpp	(revision 14167)
+++ scribus/scpainter.cpp	(revision 14168)
@@ -30,6 +30,7 @@
 	m_width = w;
 	m_height= h;
 	m_stroke = QColor(0,0,0);
+	strokeMode = 0;
 	m_fill = QColor(0,0,0);
 	fill_trans = 1.0;
 	stroke_trans = 1.0;
@@ -68,6 +69,7 @@
 	m_width = w;
 	m_height= h;
 	m_stroke = QColor(0,0,0);
+	strokeMode = 0;
 	m_fill = QColor(0,0,0);
 	fill_trans = 1.0;
 	stroke_trans = 1.0;
@@ -107,6 +109,7 @@
 	m_width = w;
 	m_height= h;
 	m_stroke = QColor(0,0,0);
+	strokeMode = 0;
 	m_fill = QColor(0,0,0);
 	fill_trans = 1.0;
 	stroke_trans = 1.0;
@@ -790,12 +793,21 @@
 	fillMode = fill;
 }
 
+void ScPainter::setStrokeMode( int stroke )
+{
+	strokeMode = stroke;
+}
+
 void ScPainter::setGradient(VGradient::VGradientType mode, FPoint orig, FPoint vec, FPoint foc)
 {
 	fill_gradient.setType(mode);
 	fill_gradient.setOrigin(orig);
 	fill_gradient.setVector(vec);
 	fill_gradient.setFocalPoint(foc);
+	stroke_gradient.setType(mode);
+	stroke_gradient.setOrigin(orig);
+	stroke_gradient.setVector(vec);
+	stroke_gradient.setFocalPoint(foc);
 }
 
 void ScPainter::fillTextPath()
@@ -990,7 +1002,6 @@
 			cairo_pattern_set_filter(m_pat, CAIRO_FILTER_BEST);
 			cairo_matrix_t matrix;
 			QTransform qmatrix;
-//			qmatrix.scale(m_zoomFactor, m_zoomFactor);
 			qmatrix.translate(patternOffsetX, patternOffsetY);
 			qmatrix.rotate(patternRotation);
 			qmatrix.scale(patternScaleX, patternScaleY);
@@ -1016,13 +1027,7 @@
 			cairo_set_dash( m_cr, m_array.data(), m_array.count(), m_offset);
 		else
 			cairo_set_dash( m_cr, NULL, 0, 0 );
-		double r, g, b;
-		m_stroke.getRgbF(&r, &g, &b);
-		cairo_set_source_rgba( m_cr, r, g, b, stroke_trans );
-//		if (stroke_trans != 1.0)
-			cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER);
-//		else
-//			cairo_set_operator(m_cr, CAIRO_OPERATOR_SOURCE);
+		cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER);
 		if( PLineEnd == Qt::RoundCap )
 			cairo_set_line_cap (m_cr, CAIRO_LINE_CAP_ROUND);
 		else if( PLineEnd == Qt::SquareCap )
@@ -1035,9 +1040,74 @@
 			cairo_set_line_join( m_cr, CAIRO_LINE_JOIN_BEVEL );
 		else if( PLineJoin == Qt::MiterJoin )
 			cairo_set_line_join( m_cr, CAIRO_LINE_JOIN_MITER );
-		cairo_stroke_preserve( m_cr );
+		if (strokeMode == 3)
+		{
+			cairo_push_group(m_cr);
+			cairo_set_antialias(m_cr, CAIRO_ANTIALIAS_NONE);
+			cairo_surface_t *image2 = cairo_image_surface_create_for_data ((uchar*)m_pattern->getPattern()->bits(), CAIRO_FORMAT_ARGB32, m_pattern->getPattern()->width(), m_pattern->getPattern()->height(), m_pattern->getPattern()->width()*4);
+			cairo_pattern_t *m_pat = cairo_pattern_create_for_surface(image2);
+			cairo_pattern_set_extend(m_pat, CAIRO_EXTEND_REPEAT);
+			cairo_pattern_set_filter(m_pat, CAIRO_FILTER_BEST);
+			cairo_matrix_t matrix;
+			QTransform qmatrix;
+			qmatrix.translate(-LineWidth / 2.0, -LineWidth / 2.0);
+			qmatrix.translate(patternOffsetX, patternOffsetY);
+			qmatrix.rotate(patternRotation);
+			qmatrix.scale(patternScaleX, patternScaleY);
+			qmatrix.scale(m_pattern->width / static_cast<double>(m_pattern->getPattern()->width()), m_pattern->height / static_cast<double>(m_pattern->getPattern()->height()));
+			cairo_matrix_init(&matrix, qmatrix.m11(), qmatrix.m12(), qmatrix.m21(), qmatrix.m22(), qmatrix.dx(), qmatrix.dy());
+			cairo_matrix_invert(&matrix);
+			cairo_pattern_set_matrix (m_pat, &matrix);
+			cairo_set_source (m_cr, m_pat);
+			cairo_stroke_preserve( m_cr );
+			cairo_pattern_destroy (m_pat);
+			cairo_surface_destroy (image2);
+			cairo_set_antialias(m_cr, CAIRO_ANTIALIAS_DEFAULT);
+			cairo_pop_group_to_source (m_cr);
+			cairo_paint_with_alpha (m_cr, stroke_trans);
+		}
+		else if (strokeMode == 2)
+		{
+			cairo_push_group(m_cr);
+			cairo_pattern_t *pat;
+			double x1 = stroke_gradient.origin().x();
+			double y1 = stroke_gradient.origin().y();
+			double x2 = stroke_gradient.vector().x();
+			double y2 = stroke_gradient.vector().y();
+			if (stroke_gradient.type() == VGradient::linear)
+				pat = cairo_pattern_create_linear (x1, y1,  x2, y2);
+			else
+				pat = cairo_pattern_create_radial (x1, y1, 0.1, x1, y1, sqrt(pow(x2 - x1, 2) + pow(y2 - y1,2)));
+			QList<VColorStop*> colorStops = stroke_gradient.colorStops();
+			QColor qStopColor;
+			for( int offset = 0 ; offset < colorStops.count() ; offset++ )
+			{
+				qStopColor = colorStops[ offset ]->color;
+				int h, s, v, sneu, vneu;
+				int shad = colorStops[offset]->shade;
+				qStopColor.getHsv(&h, &s, &v);
+				sneu = s * shad / 100;
+				vneu = 255 - ((255 - v) * shad / 100);
+				qStopColor.setHsv(h, sneu, vneu);
+				double a = colorStops[offset]->opacity;
+				double r, g, b;
+				qStopColor.getRgbF(&r, &g, &b);
+				cairo_pattern_add_color_stop_rgba (pat, colorStops[ offset ]->rampPoint, r, g, b, a);
+			}
+			cairo_set_source (m_cr, pat);
+			cairo_stroke_preserve( m_cr );
+			cairo_pattern_destroy (pat);
+			cairo_pop_group_to_source (m_cr);
+			cairo_paint_with_alpha (m_cr, stroke_trans);
+		}
+		else
+		{
+			double r, g, b;
+			m_stroke.getRgbF(&r, &g, &b);
+			cairo_set_source_rgba( m_cr, r, g, b, stroke_trans );
+			cairo_stroke_preserve( m_cr );
+		}
 	}
-//	cairo_set_operator(m_cr, CAIRO_OPERATOR_OVER);
 	cairo_restore( m_cr );
 }
 #else
@@ -1096,7 +1166,7 @@
 			qmatrix.scale(m_pattern->width / static_cast<double>(m_pattern->getPattern()->width()), m_pattern->height / static_cast<double>(m_pattern->getPattern()->height()));
 			QBrush brush = QBrush(*m_pattern->getPattern());
 			brush.setTransform(qmatrix);
-			painter.rotate(0.0001);	// hack to get Qt-4's strange pattern rendering working
+//			painter.rotate(0.0001);	// hack to get Qt-4's strange pattern rendering working
 			painter.setOpacity(fill_trans);
 			painter.fillPath(m_path, brush);
 			painter.setRenderHint(QPainter::Antialiasing, true);
@@ -1139,6 +1209,48 @@
 			pen.setCapStyle(PLineEnd);
 			pen.setJoinStyle(PLineJoin);
 		}
+		if (strokeMode == 3)
+		{
+			QTransform qmatrix;
+			qmatrix.translate(-LineWidth / 2.0, -LineWidth / 2.0);
+			qmatrix.translate(patternOffsetX, patternOffsetY);
+			qmatrix.rotate(patternRotation);
+			qmatrix.scale(patternScaleX, patternScaleY);
+			qmatrix.scale(m_pattern->width / static_cast<double>(m_pattern->getPattern()->width()), m_pattern->height / static_cast<double>(m_pattern->getPattern()->height()));
+			QBrush brush = QBrush(*m_pattern->getPattern());
+			brush.setTransform(qmatrix);
+//			painter.rotate(0.0001);	// hack to get Qt-4's strange pattern rendering working
+			painter.setOpacity(stroke_trans);
+			pen.setBrush(brush);
+		}
+		else if (strokeMode == 2)
+		{
+			QGradient pat;
+			double x1 = stroke_gradient.origin().x();
+			double y1 = stroke_gradient.origin().y();
+			double x2 = stroke_gradient.vector().x();
+			double y2 = stroke_gradient.vector().y();
+			if (stroke_gradient.type() == VGradient::linear)
+				pat = QLinearGradient(x1, y1,  x2, y2);
+			else
+				pat = QRadialGradient(x1, y1, sqrt(pow(x2 - x1, 2) + pow(y2 - y1,2)), x1, y1);
+			QList<VColorStop*> colorStops = stroke_gradient.colorStops();
+			QColor qStopColor;
+			for( int offset = 0 ; offset < colorStops.count() ; offset++ )
+			{
+				qStopColor = colorStops[ offset ]->color;
+				int h, s, v, sneu, vneu;
+				int shad = colorStops[offset]->shade;
+				qStopColor.getHsv(&h, &s, &v);
+				sneu = s * shad / 100;
+				vneu = 255 - ((255 - v) * shad / 100);
+				qStopColor.setHsv(h, sneu, vneu);
+				qStopColor.setAlphaF(colorStops[offset]->opacity);
+				pat.setColorAt(colorStops[ offset ]->rampPoint, qStopColor);
+			}
+			painter.setOpacity(stroke_trans);
+			pen.setBrush(pat);
+		}
 		painter.strokePath(m_path, pen);
 	}
 	painter.restore();
Index: scribus/pageitem.cpp
===================================================================
--- scribus/pageitem.cpp	(revision 14167)
+++ scribus/pageitem.cpp	(revision 14168)
@@ -241,7 +241,19 @@
 	m_annotation(other.m_annotation),
 	PicArt(other.PicArt),
 	m_lineWidth(other.m_lineWidth),
-	Oldm_lineWidth(other.Oldm_lineWidth)
+	Oldm_lineWidth(other.Oldm_lineWidth),
+	patternStrokeVal(other.patternStrokeVal),
+	patternStrokeScaleX(other.patternStrokeScaleX),
+	patternStrokeScaleY(other.patternStrokeScaleY),
+	patternStrokeOffsetX(other.patternStrokeOffsetX),
+	patternStrokeOffsetY(other.patternStrokeOffsetY),
+	patternStrokeRotation(other.patternStrokeRotation),
+	gradientStrokeVal(other.gradientStrokeVal),
+	GrTypeStroke(other.GrTypeStroke),
+	GrStrokeStartX(other.GrStrokeStartX),
+	GrStrokeStartY(other.GrStrokeStartY),
+	GrStrokeEndX(other.GrStrokeEndX),
+	GrStrokeEndY(other.GrStrokeEndY)
 {
 	QString tmp;
 	m_Doc->TotalItems++;
@@ -311,12 +323,24 @@
 	GrEndX = w;
 	GrEndY = 0;
 	gradientVal = "";
+	GrTypeStroke = 0;
+	GrStrokeStartX = 0;
+	GrStrokeStartY = 0;
+	GrStrokeEndX = w;
+	GrStrokeEndY = 0;
+	gradientStrokeVal = "";
 	patternVal = "";
 	patternScaleX = 100;
 	patternScaleY = 100;
 	patternOffsetX = 0;
 	patternOffsetY = 0;
 	patternRotation = 0;
+	patternStrokeVal = "";
+	patternStrokeScaleX = 100;
+	patternStrokeScaleY = 100;
+	patternStrokeOffsetX = 0;
+	patternStrokeOffsetY = 0;
+	patternStrokeRotation = 0;
 	m_lineWidth = w2;
 	Oldm_lineWidth = w2;
 	PLineArt = Qt::PenStyle(m_Doc->itemToolPrefs.shapeLineStyle);
@@ -442,6 +466,52 @@
 	DashOffset = 0;
 	fillRule = true;
 	doOverprint = false;
+	stroke_gradient = VGradient(VGradient::linear);
+	stroke_gradient.clearStops();
+	if (lineColorVal != CommonStrings::None)
+	{
+		const ScColor& col = m_Doc->PageColors[lineColorVal];
+		QColor qcol = ScColorEngine::getRGBColor(col, m_Doc);
+		stroke_gradient.addStop(qcol, 0.0, 0.5, 1.0, lineColorVal, 100);
+		stroke_gradient.addStop(qcol, 1.0, 0.5, 1.0, lineColorVal, 100);
+	}
+	else
+	{
+		if (m_Doc->itemToolPrefs.shapeLineColor != CommonStrings::None)
+		{
+			const ScColor& col = m_Doc->PageColors[m_Doc->itemToolPrefs.shapeLineColor];
+			QColor qcol = ScColorEngine::getRGBColor(col, m_Doc);
+			stroke_gradient.addStop(qcol, 0.0, 0.5, 1.0, m_Doc->itemToolPrefs.shapeLineColor, 100);
+			stroke_gradient.addStop(qcol, 1.0, 0.5, 1.0, m_Doc->itemToolPrefs.shapeLineColor, 100);
+		}
+		else
+		{
+			if (fillColorVal != CommonStrings::None)
+			{
+				const ScColor& col = m_Doc->PageColors[fillColorVal];
+				QColor qcol = ScColorEngine::getRGBColor(col, m_Doc);
+				stroke_gradient.addStop(qcol, 0.0, 0.5, 1.0, fillColorVal, 100);
+				stroke_gradient.addStop(qcol, 1.0, 0.5, 1.0, fillColorVal, 100);
+			}
+			else
+			{
+				if (m_Doc->itemToolPrefs.shapeLineColor != CommonStrings::None)
+				{
+					const ScColor& col = m_Doc->PageColors[m_Doc->itemToolPrefs.shapeFillColor];
+					QColor qcol = ScColorEngine::getRGBColor(col, m_Doc);
+					stroke_gradient.addStop(qcol, 0.0, 0.5, 1.0, m_Doc->itemToolPrefs.shapeFillColor, 100);
+					stroke_gradient.addStop(qcol, 1.0, 0.5, 1.0, m_Doc->itemToolPrefs.shapeFillColor, 100);
+				}
+				else if (m_Doc->PageColors.contains("Black"))
+				{
+					const ScColor& col = m_Doc->PageColors["Black"];
+					QColor qcol = ScColorEngine::getRGBColor(col, m_Doc);
+					stroke_gradient.addStop(qcol, 0.0, 0.5, 1.0, "Black", 100);
+					stroke_gradient.addStop(qcol, 1.0, 0.5, 1.0, "Black", 100);
+				}
+			}
+		}
+	}
 	fill_gradient = VGradient(VGradient::linear);
 	fill_gradient.clearStops();
 	if (fillColorVal != CommonStrings::None)
@@ -1094,16 +1164,11 @@
 			else
 				p->setFillMode(ScPainter::None);
 		}
-		if (lineColor() != CommonStrings::None)
+		if ((lineColor() != CommonStrings::None) || (!patternStrokeVal.isEmpty()))
 		{
-//			if ((m_lineWidth == 0) && ! asLine())
-//				p->setLineWidth(0);
-//			else
-//			{
-				p->setPen(strokeQColor, m_lineWidth, PLineArt, PLineEnd, PLineJoin);
-				if (DashValues.count() != 0)
-					p->setDash(DashValues, DashOffset);
-//			}
+			p->setPen(strokeQColor, m_lineWidth, PLineArt, PLineEnd, PLineJoin);
+			if (DashValues.count() != 0)
+				p->setDash(DashValues, DashOffset);
 		}
 		else
 			p->setLineWidth(0);
@@ -1163,30 +1228,80 @@
 			{
 				if (lineBlendmode() != 0)
 					p->beginLayer(1.0 - lineTransparency(), lineBlendmode());
-//				if (lineColor() != CommonStrings::None)
-//				{
-//					p->setPen(strokeQColor, m_lineWidth, PLineArt, PLineEnd, PLineJoin);
-//					if (DashValues.count() != 0)
-//						p->setDash(DashValues, DashOffset);
-//				}
-//				else
-//					p->setLineWidth(0);
+				if ((lineColor() != CommonStrings::None) || (!patternStrokeVal.isEmpty()))
+				{
+					p->setPen(strokeQColor, m_lineWidth, PLineArt, PLineEnd, PLineJoin);
+					if (DashValues.count() != 0)
+						p->setDash(DashValues, DashOffset);
+				}
+				else
+					p->setLineWidth(0);
 				if (!isTableItem)
 				{
 					if ((itemType() == LatexFrame) || (itemType() == ImageFrame) || (itemType() == OSGFrame))
 						p->setupPolygon(&PoLine);
 					if (NamedLStyle.isEmpty())
 					{
-						if (lineColor() != CommonStrings::None)
+						if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal)))
 						{
+							p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation);
+							p->setStrokeMode(ScPainter::Pattern);
+						}
+						else if (lineColor() != CommonStrings::None)
+						{
+							p->setStrokeMode(ScPainter::Solid);
 							p->setPen(strokeQColor, m_lineWidth, PLineArt, PLineEnd, PLineJoin);
 							if (DashValues.count() != 0)
 								p->setDash(DashValues, DashOffset);
-							p->strokePath();
 						}
+						p->strokePath();
+/*
+			else if ((GrType > 0) && (GrType < 8))
+			{
+				if ((!gradientVal.isEmpty()) && (!m_Doc->docGradients.contains(gradientVal)))
+					gradientVal = "";
+				if (!(gradientVal.isEmpty()) && (m_Doc->docGradients.contains(gradientVal)))
+					fill_gradient = m_Doc->docGradients[gradientVal];
+				if (fill_gradient.Stops() < 2) // fall back to solid filling if there are not enough colorstops in the gradient.
+				{
+					if (fillColor() != CommonStrings::None)
+					{
+						p->setBrush(fillQColor);
+						p->setFillMode(ScPainter::Solid);
 					}
 					else
+						p->setFillMode(ScPainter::None);
+				}
+				else
+				{
+					p->setStrokeMode(ScPainter::Gradient);
+					p->stroke_gradient = fill_gradient;
+					QTransform grm;
+					grm.rotate(Rot);
+					FPointArray gra;
+					switch (GrType)
 					{
+						case 1:
+						case 2:
+						case 3:
+						case 4:
+						case 6:
+							p->setGradient(VGradient::linear, FPoint(GrStartX, GrStartY), FPoint(GrEndX, GrEndY));
+							break;
+						case 5:
+						case 7:
+							gra.setPoints(2, GrStartX, GrStartY, GrEndX, GrEndY);
+							p->setGradient(VGradient::radial, gra.point(0), gra.point(1), gra.point(0));
+							break;
+					}
+				}
+				p->strokePath();
+			}
+*/
+					}
+					else
+					{
+						p->setStrokeMode(ScPainter::Solid);
 						multiLine ml = m_Doc->MLineStyles[NamedLStyle];
 						QColor tmp;
 						for (int it = ml.size()-1; it > -1; it--)
@@ -2260,6 +2375,28 @@
 	GrEndY   = endY;
 }
 
+void PageItem::setStrokeGradient(const QString &newGradient)
+{
+	if (gradientStrokeVal != newGradient)
+		gradientStrokeVal = newGradient;
+}
+
+void PageItem::strokeGradientVector(double& startX, double& startY, double& endX, double& endY) const
+{
+	startX = GrStrokeStartX;
+	startY = GrStrokeStartY;
+	endX   = GrStrokeEndX;
+	endY   = GrStrokeEndY;
+}
+
+void PageItem::setStrokeGradientVector(double startX, double startY, double endX, double endY)
+{
+	GrStrokeStartX = startX;
+	GrStrokeStartY = startY;
+	GrStrokeEndX   = endX;
+	GrStrokeEndY   = endY;
+}
+
 void PageItem::setPatternTransform(double scaleX, double scaleY, double offsetX, double offsetY, double rotation)
 {
 	patternScaleX = scaleX;
@@ -2452,6 +2589,30 @@
 //CB unused in 135	emit colors(lineColorVal, fillColorVal, lineShadeVal, fillShadeVal);
 }
 
+void PageItem::setStrokePattern(const QString &newPattern)
+{
+	if (patternStrokeVal != newPattern)
+		patternStrokeVal = newPattern;
+}
+
+void PageItem::setStrokePatternTransform(double scaleX, double scaleY, double offsetX, double offsetY, double rotation)
+{
+	patternStrokeScaleX = scaleX;
+	patternStrokeScaleY = scaleY;
+	patternStrokeOffsetX = offsetX;
+	patternStrokeOffsetY = offsetY;
+	patternStrokeRotation = rotation;
+}
+
+void  PageItem::strokePatternTransform(double &scaleX, double &scaleY, double &offsetX, double &offsetY, double &rotation) const
+{
+	 scaleX = patternStrokeScaleX;
+	 scaleY = patternStrokeScaleY;
+	 offsetX = patternStrokeOffsetX;
+	 offsetY = patternStrokeOffsetY;
+	 rotation = patternStrokeRotation;
+}
+
 void PageItem::setLineQColor()
 {
 	if (lineColorVal != CommonStrings::None)
@@ -3953,6 +4114,14 @@
 	if (it != newNames.patterns().end())
 		setPattern(*it);
 	
+	it = newNames.patterns().find(strokePattern());
+	if (it != newNames.patterns().end())
+		setStrokePattern(*it);
+	
+	it = newNames.gradients().find(strokeGradient());
+	if (it != newNames.gradients().end())
+		setStrokeGradient(*it);
+	
 	it = newNames.gradients().find(gradient());
 	if (it != newNames.gradients().end())
 		setGradient(*it);
@@ -4971,14 +5140,19 @@
 	{
 		if (NamedLStyle.isEmpty())
 		{
-			if (lineColor() != CommonStrings::None)
+			if ((!patternStrokeVal.isEmpty()) && (m_Doc->docPatterns.contains(patternStrokeVal)))
 			{
+				p->setPattern(&m_Doc->docPatterns[patternStrokeVal], patternStrokeScaleX, patternStrokeScaleY, patternStrokeOffsetX, patternStrokeOffsetY, patternStrokeRotation);
+				p->setFillMode(ScPainter::Pattern);
+			}
+			else if (lineColor() != CommonStrings::None)
+			{
 				p->setBrush(strokeQColor);
 				p->setBrushOpacity(1.0 - lineTransparency());
 				p->setLineWidth(0);
 				p->setFillMode(ScPainter::Solid);
-				p->fillPath();
 			}
+			p->fillPath();
 		}
 		else
 		{
@@ -5492,6 +5666,14 @@
 				GrStartY = gr.point(0).y();
 				GrEndX = gr.point(1).x();
 				GrEndY = gr.point(1).y();
+				FPointArray gr2;
+				gr2.addPoint(GrStrokeStartX, GrStrokeStartY);
+				gr2.addPoint(GrStrokeEndX, GrStrokeEndY);
+				gr2.map(ma);
+				GrStrokeStartX = gr2.point(0).x();
+				GrStrokeStartY = gr2.point(0).y();
+				GrStrokeEndX = gr2.point(1).x();
+				GrStrokeEndY = gr2.point(1).y();
 				ContourLine.map(ma);
 				if (FrameType > 2)
 				{
@@ -5544,6 +5726,14 @@
 			GrStartY = gr.point(0).y();
 			GrEndX = gr.point(1).x();
 			GrEndY = gr.point(1).y();
+			FPointArray gr2;
+			gr2.addPoint(GrStrokeStartX, GrStrokeStartY);
+			gr2.addPoint(GrStrokeEndX, GrStrokeEndY);
+			gr2.map(ma);
+			GrStrokeStartX = gr2.point(0).x();
+			GrStrokeStartY = gr2.point(0).y();
+			GrStrokeEndX = gr2.point(1).x();
+			GrStrokeEndY = gr2.point(1).y();
 			PoLine.map(ma);
 			ContourLine.map(ma);
 			if (asPathText())
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h	(revision 14167)
+++ scribus/scribusdoc.h	(revision 14168)
@@ -1222,6 +1222,8 @@
 	void itemSelection_SetItemGradFill(int typ);
 	void itemSelection_SetItemPatternFill(QString pattern);
 	void itemSelection_SetItemPatternProps(double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
+	void itemSelection_SetItemStrokePattern(QString pattern);
+	void itemSelection_SetItemStrokePatternProps(double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
 
 	void undoRedoBegin();
 	void undoRedoDone();
Index: scribus/ui/cpalette.cpp
===================================================================
--- scribus/ui/cpalette.cpp	(revision 14167)
+++ scribus/ui/cpalette.cpp	(revision 14168)
@@ -42,6 +42,7 @@
 #include <QToolTip>
 #include <QVBoxLayout>
 #include <QCheckBox>
+#include <QDebug>
 
 #include "colorlistbox.h"
 #include "sccombobox.h"
@@ -319,8 +320,12 @@
 	connect(editPatternProps, SIGNAL(clicked()), this, SLOT(changePatternProps()));
 	connect(namedGradient, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
 	connect(overPrintCombo, SIGNAL(activated(int)), this, SIGNAL(NewOverprint(int)));
+	connect(patternBoxStroke, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPatternS(QListWidgetItem*)));
+	connect(tabWidgetStroke, SIGNAL(currentChanged(int)), this, SLOT(slotGradStroke(int)));
+	connect(editPatternPropsStroke, SIGNAL(clicked()), this, SLOT(changePatternPropsStroke()));
 	editFillColorSelector->setChecked(true);
 	editFillColorSelectorButton();
+	tabWidgetStroke->setTabEnabled(1, false);
 }
 
 void Cpalette::setCurrentItem(PageItem* item)
@@ -373,9 +378,19 @@
 		gradEdit->setGradientEditable(true);
 	}
 	if (patternList->count() == 0)
+	{
+		tabWidgetStroke->setTabEnabled(2, false);
 		tabWidget->setTabEnabled(2, false);
+	}
 	else
+	{
+		tabWidgetStroke->setTabEnabled(2, true);
 		tabWidget->setTabEnabled(2, true);
+	}
+	if (currentItem->strokePattern().isEmpty())
+		tabWidgetStroke->setCurrentIndex(0);
+	else
+		tabWidgetStroke->setCurrentIndex(2);
 	connect(namedGradient, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
 }
 
@@ -392,6 +407,7 @@
 		if (currentDoc != NULL)
 			currentDoc->getUsedColors(colorList);
 	}
+	gradEditStroke->setColors(colorList);
 	gradEdit->setColors(colorList);
 	colorListFill->insertItems(colorList, ColorListBox::fancyPixmap);
 	colorListStroke->insertItems(colorList, ColorListBox::fancyPixmap);
@@ -464,7 +480,7 @@
 			colorListFill->setCurrentItem(cCol[0]);
 	}
 	else
-		colorListStroke->setCurrentRow(0);
+		colorListFill->setCurrentRow(0);
 	connect(fillShade, SIGNAL(valueChanged(int)), this, SIGNAL(NewBrushShade(int)));
 	connect(strokeShade, SIGNAL(valueChanged(int)), this, SIGNAL(NewPenShade(int)));
 	connect(colorListStroke, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(selectColorS(QListWidgetItem*)));
@@ -538,6 +554,9 @@
 	namedGradient->clear();
 	namedGradient->setIconSize(QSize(48, 12));
 	namedGradient->addItem( tr("Custom"));
+	namedGradientStroke->clear();
+	namedGradientStroke->setIconSize(QSize(48, 12));
+	namedGradientStroke->addItem( tr("Custom"));
 	for (QMap<QString, VGradient>::Iterator it = gradientList->begin(); it != gradientList->end(); ++it)
 	{
 		QImage pixm(48, 12, QImage::Format_ARGB32);
@@ -558,6 +577,7 @@
 		QPixmap pm;
 		pm = QPixmap::fromImage(pixm);
 		namedGradient->addItem(pm, it.key());
+		namedGradientStroke->addItem(pm, it.key());
 	}
 	connect(namedGradient, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
 }
@@ -589,6 +609,8 @@
 	disconnect(patternBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPattern(QListWidgetItem*)));
 	patternBox->clear();
 	patternBox->setIconSize(QSize(48, 48));
+	patternBoxStroke->clear();
+	patternBoxStroke->setIconSize(QSize(48, 48));
 	for (QMap<QString, ScPattern>::Iterator it = patternList->begin(); it != patternList->end(); ++it)
 	{
 		QPixmap pm;
@@ -604,8 +626,11 @@
 		p.end();
 		QListWidgetItem *item = new QListWidgetItem(pm2, it.key(), patternBox);
 		item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+		QListWidgetItem *itemS = new QListWidgetItem(pm2, it.key(), patternBoxStroke);
+		itemS->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
 	}
 	patternBox->clearSelection();
+	patternBoxStroke->clearSelection();
 	connect(patternBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPattern(QListWidgetItem*)));
 }
 
@@ -622,6 +647,32 @@
 	emit NewPattern(c->text());
 }
 
+void Cpalette::selectPatternS(QListWidgetItem *c)
+{
+	if (c == NULL)
+		return;
+	emit NewPatternS(c->text());
+}
+
+void Cpalette::setActPatternStroke(QString pattern, double scaleX, double scaleY, double offsetX, double offsetY, double rotation)
+{
+	disconnect(patternBoxStroke, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPatternS(QListWidgetItem*)));
+	QList<QListWidgetItem*> itl = patternBoxStroke->findItems(pattern, Qt::MatchExactly);
+	if (itl.count() != 0)
+	{
+		QListWidgetItem *it = itl[0];
+		patternBoxStroke->setCurrentItem(it);
+	}
+	else
+		patternBoxStroke->clearSelection();
+	m_Pattern_scaleXS = scaleX;
+	m_Pattern_scaleYS = scaleX;
+	m_Pattern_offsetXS = offsetX;
+	m_Pattern_offsetYS = offsetY;
+	m_Pattern_rotationS = rotation;
+	connect(patternBoxStroke, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPatternS(QListWidgetItem*)));
+}
+
 void Cpalette::setActPattern(QString pattern, double scaleX, double scaleY, double offsetX, double offsetY, double rotation)
 {
 	disconnect(patternBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPattern(QListWidgetItem*)));
@@ -641,6 +692,35 @@
 	connect(patternBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(selectPattern(QListWidgetItem*)));
 }
 
+void Cpalette::slotGradStroke(int number)
+{
+	if (number == 1)
+	{
+//		disconnect(namedGradientStroke, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
+		if (!currentItem->strokeGradient().isEmpty())
+		{
+			setCurrentComboItem(namedGradientStroke, currentItem->strokeGradient());
+			gradEditStroke->setGradient(gradientList->value(currentItem->strokeGradient()));
+			gradEditStroke->setGradientEditable(false);
+		}
+		else
+		{
+			namedGradientStroke->setCurrentIndex(0);
+			gradEditStroke->setGradient(currentItem->stroke_gradient);
+			gradEditStroke->setGradientEditable(true);
+		}
+//		if (gradientType->currentIndex() == 0)
+//			emit NewGradient(6);
+//		else
+//			currentItem->GrType = 7;
+//		connect(namedGradient, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
+	}
+//	else if (number == 2)
+//		emit NewGradient(8);
+	else
+		emit NewPatternS("");
+}
+
 void Cpalette::ChooseGrad(int number)
 {
 	disconnect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotGrad(int)));
@@ -691,7 +771,7 @@
 		if (gradientType->currentIndex() == 0)
 			emit NewGradient(6);
 		else
-			currentItem->GrType = 7;
+			emit NewGradient(7);
 		connect(namedGradient, SIGNAL(activated(const QString &)), this, SLOT(setNamedGradient(const QString &)));
 	}
 	else if (number == 2)
@@ -763,6 +843,24 @@
 	emit NewGradient(8);
 }
 
+void Cpalette::changePatternPropsStroke()
+{
+	PatternPropsDialog *dia = new PatternPropsDialog(this, currentUnit);
+	dia->spinXscaling->setValue(m_Pattern_scaleXS);
+	dia->spinYscaling->setValue(m_Pattern_scaleYS);
+	dia->spinXoffset->setValue(m_Pattern_offsetXS);
+	dia->spinYoffset->setValue(m_Pattern_offsetYS);
+	dia->spinAngle->setValue(m_Pattern_rotationS);
+	connect(dia, SIGNAL(NewPatternProps(double, double, double, double, double)), this, SIGNAL(NewPatternPropsS(double, double, double, double, double)));
+	dia->exec();
+	m_Pattern_scaleXS = dia->spinXscaling->value();
+	m_Pattern_scaleYS = dia->spinYscaling->value();
+	m_Pattern_offsetXS = dia->spinXoffset->value();
+	m_Pattern_offsetYS = dia->spinYoffset->value();
+	m_Pattern_rotationS = dia->spinAngle->value();
+	delete dia;
+}
+
 void Cpalette::unitChange(double, double, int unitIndex)
 {
 	if (CGradDia)
Index: scribus/ui/colorpalette.ui
===================================================================
--- scribus/ui/colorpalette.ui	(revision 14167)
+++ scribus/ui/colorpalette.ui	(revision 14168)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>236</width>
-    <height>405</height>
+    <width>228</width>
+    <height>389</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -76,40 +76,201 @@
      </property>
      <widget class="QWidget" name="pageStroke">
       <layout class="QGridLayout" name="gridLayout_3">
+       <property name="margin">
+        <number>5</number>
+       </property>
+       <property name="spacing">
+        <number>2</number>
+       </property>
        <item row="0" column="0" colspan="2">
-        <widget class="ColorListBox" name="colorListStroke"/>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="label">
-         <property name="text">
-          <string>Shade:</string>
+        <widget class="QTabWidget" name="tabWidgetStroke">
+         <property name="currentIndex">
+          <number>0</number>
          </property>
+         <widget class="QWidget" name="tabSolid_2">
+          <attribute name="title">
+           <string>Solid</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_3">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
+           <item>
+            <widget class="ColorListBox" name="colorListStroke"/>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_5">
+             <item>
+              <widget class="QLabel" name="label_8">
+               <property name="text">
+                <string>Shade:</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QSpinBox" name="strokeShade">
+               <property name="toolTip">
+                <string>Saturation of color</string>
+               </property>
+               <property name="suffix">
+                <string> %</string>
+               </property>
+               <property name="maximum">
+                <number>100</number>
+               </property>
+               <property name="value">
+                <number>100</number>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="tabGradient_2">
+          <attribute name="title">
+           <string>Gradient</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_5">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_6">
+             <item>
+              <widget class="QComboBox" name="gradientTypeStroke">
+               <item>
+                <property name="text">
+                 <string>Linear</string>
+                </property>
+               </item>
+               <item>
+                <property name="text">
+                 <string>Radial</string>
+                </property>
+               </item>
+              </widget>
+             </item>
+             <item>
+              <widget class="QToolButton" name="gradEditButtonStroke">
+               <property name="toolTip">
+                <string>Move the start of the gradient vector with the left mouse button pressed and move the end of the gradient vector with the right mouse button pressed</string>
+               </property>
+               <property name="text">
+                <string>Move Vector</string>
+               </property>
+               <property name="checkable">
+                <bool>true</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <widget class="GradientEditor" name="gradEditStroke">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="minimumSize">
+              <size>
+               <width>200</width>
+               <height>173</height>
+              </size>
+             </property>
+             <property name="frameShape">
+              <enum>QFrame::NoFrame</enum>
+             </property>
+             <property name="frameShadow">
+              <enum>QFrame::Raised</enum>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="ScComboBox" name="namedGradientStroke"/>
+           </item>
+          </layout>
+         </widget>
+         <widget class="QWidget" name="tabPattern_2">
+          <attribute name="title">
+           <string>Pattern</string>
+          </attribute>
+          <layout class="QVBoxLayout" name="verticalLayout_6">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
+           <item>
+            <widget class="QListWidget" name="patternBoxStroke">
+             <property name="movement">
+              <enum>QListView::Snap</enum>
+             </property>
+             <property name="flow">
+              <enum>QListView::LeftToRight</enum>
+             </property>
+             <property name="isWrapping" stdset="0">
+              <bool>true</bool>
+             </property>
+             <property name="resizeMode">
+              <enum>QListView::Adjust</enum>
+             </property>
+             <property name="viewMode">
+              <enum>QListView::IconMode</enum>
+             </property>
+             <property name="wordWrap">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_7">
+             <property name="spacing">
+              <number>5</number>
+             </property>
+             <item>
+              <widget class="QToolButton" name="editPatternPropsStroke">
+               <property name="text">
+                <string>Properties...</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <spacer name="horizontalSpacer_4">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </widget>
         </widget>
        </item>
-       <item row="1" column="1">
-        <widget class="QSpinBox" name="strokeShade">
-         <property name="toolTip">
-          <string>Saturation of color</string>
-         </property>
-         <property name="suffix">
-          <string> %</string>
-         </property>
-         <property name="maximum">
-          <number>100</number>
-         </property>
-         <property name="value">
-          <number>100</number>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="0">
+       <item row="1" column="0">
         <widget class="QLabel" name="label_2">
          <property name="text">
           <string>Opacity:</string>
          </property>
         </widget>
        </item>
-       <item row="2" column="1">
+       <item row="1" column="1">
         <widget class="QSpinBox" name="strokeOpacity">
          <property name="toolTip">
           <string>Set the transparency for the color selected</string>
@@ -128,14 +289,14 @@
          </property>
         </widget>
        </item>
-       <item row="3" column="0">
+       <item row="2" column="0">
         <widget class="QLabel" name="label_3">
          <property name="text">
           <string>Blend Mode:</string>
          </property>
         </widget>
        </item>
-       <item row="3" column="1">
+       <item row="2" column="1">
         <widget class="ScComboBox" name="blendModeStroke">
          <item>
           <property name="text">
@@ -239,6 +400,12 @@
            <string>Solid</string>
           </attribute>
           <layout class="QVBoxLayout" name="verticalLayout_2">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
            <item>
             <widget class="ColorListBox" name="colorListFill"/>
            </item>
@@ -276,6 +443,12 @@
            <string>Gradient</string>
           </attribute>
           <layout class="QVBoxLayout" name="verticalLayout_4">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_3">
              <item>
@@ -339,6 +512,12 @@
            <string>Pattern</string>
           </attribute>
           <layout class="QVBoxLayout" name="verticalLayout">
+           <property name="spacing">
+            <number>2</number>
+           </property>
+           <property name="margin">
+            <number>5</number>
+           </property>
            <item>
             <widget class="QListWidget" name="patternBox">
              <property name="movement">
Index: scribus/ui/cpalette.h
===================================================================
--- scribus/ui/cpalette.h	(revision 14167)
+++ scribus/ui/cpalette.h	(revision 14168)
@@ -148,12 +148,15 @@
 	void SetGradients(QMap<QString, VGradient> *docGradients);
 	void setNamedGradient(const QString &name);
 	void selectPattern(QListWidgetItem *c);
+	void selectPatternS(QListWidgetItem *c);
 	void updatePatternList();
 	void updateGradientList();
 	void setActPattern(QString pattern, double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
+	void setActPatternStroke(QString pattern, double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
 	void setActFarben(QString p, QString b, int shp, int shb);
 	void selectColorS(QListWidgetItem *c);
 	void selectColorF(QListWidgetItem *c);
+	void slotGradStroke(int number);
 	void ChooseGrad(int nr);
 	void slotGrad(int nr);
 	void slotGradType(int type);
@@ -162,6 +165,7 @@
 	void setActiveGradDia(bool active);
 	void setSpecialGradient(double x1, double y1, double x2, double y2);
 	void changePatternProps();
+	void changePatternPropsStroke();
 	void unitChange(double, double, int unitIndex);
 signals:
 	void NewPen(QString);
@@ -171,6 +175,8 @@
 	void NewGradient(int);
 	void NewPattern(QString);
 	void NewPatternProps(double, double, double, double, double);
+	void NewPatternS(QString);
+	void NewPatternPropsS(double, double, double, double, double);
 	void NewSpecial(double, double, double, double);
 	void NewTrans(double);
 	void NewTransS(double);
@@ -193,6 +199,11 @@
 	double m_Pattern_offsetX;
 	double m_Pattern_offsetY;
 	double m_Pattern_rotation;
+	double m_Pattern_scaleXS;
+	double m_Pattern_scaleYS;
+	double m_Pattern_offsetXS;
+	double m_Pattern_offsetYS;
+	double m_Pattern_rotationS;
 	int currentUnit;
 };
 
Index: scribus/ui/propertiespalette.cpp
===================================================================
--- scribus/ui/propertiespalette.cpp	(revision 14167)
+++ scribus/ui/propertiespalette.cpp	(revision 14168)
@@ -1862,6 +1862,8 @@
 	disconnect(this->Cpal, SIGNAL(NewPattern(QString)), 0, 0);
 	disconnect(this->Cpal, SIGNAL(NewPatternProps(double, double, double, double, double)), 0, 0);
 	disconnect(this->Cpal, SIGNAL(NewOverprint(int)), 0, 0);
+	disconnect(this->Cpal, SIGNAL(NewPatternS(QString)), 0, 0);
+	disconnect(this->Cpal, SIGNAL(NewPatternPropsS(double, double, double, double, double)), 0, 0);
 
 	doc = d;
 	CurItem = NULL;
@@ -1937,6 +1939,8 @@
 	connect(this->Cpal, SIGNAL(NewPattern(QString)), doc, SLOT(itemSelection_SetItemPatternFill(QString)));
 	connect(this->Cpal, SIGNAL(NewPatternProps(double, double, double, double, double)), doc, SLOT(itemSelection_SetItemPatternProps(double, double, double, double, double)));
 	connect(this->Cpal, SIGNAL(NewOverprint(int)), this, SLOT(handleOverprint(int)));
+	connect(this->Cpal, SIGNAL(NewPatternS(QString)), doc, SLOT(itemSelection_SetItemStrokePattern(QString)));
+	connect(this->Cpal, SIGNAL(NewPatternPropsS(double, double, double, double, double)), doc, SLOT(itemSelection_SetItemStrokePatternProps(double, double, double, double, double)));
 }
 
 void PropertiesPalette::unsetDoc()
@@ -2213,6 +2217,8 @@
 	double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
 	i->patternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
 	Cpal->setActPattern(i->pattern(), patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+	i->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+	Cpal->setActPatternStroke(i->strokePattern(), patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
 
 //CB TODO reconnect PP signals from here
 	connect(Xpos, SIGNAL(valueChanged(double)), this, SLOT(NewX()));
Index: scribus/plugins/fileloader/scribus12format/scribus12format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus12format/scribus12format.cpp	(revision 14167)
+++ scribus/plugins/fileloader/scribus12format/scribus12format.cpp	(revision 14168)
@@ -852,6 +852,20 @@
 			OB->GrShade2 = obj->attribute("GRSHADE2", "100").toInt();
 		}
 	}
+	switch (OB->GrType)
+	{
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+			OB->GrType = 6;
+			break;
+		case 5:
+			OB->GrType = 7;
+			break;
+		default:
+			break;
+	}
 	OB->Rot=ScCLocale::toDoubleC(obj->attribute("ROT"));
 	OB->PLineArt=Qt::PenStyle(obj->attribute("PLINEART").toInt());
 	OB->PLineEnd=Qt::PenCapStyle(obj->attribute("PLINEEND", "0").toInt());
Index: scribus/plugins/fileloader/scribus13format/scribus13format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus13format/scribus13format.cpp	(revision 14167)
+++ scribus/plugins/fileloader/scribus13format/scribus13format.cpp	(revision 14168)
@@ -2553,6 +2553,20 @@
 		}
 //		currItem->updateGradientVectors();
 	}
+	switch (currItem->GrType)
+	{
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+			currItem->GrType = 6;
+			break;
+		case 5:
+			currItem->GrType = 7;
+			break;
+		default:
+			break;
+	}
 	//currItem->setRedrawBounding();
 	//currItem->OwnPage = view->OnPage(currItem);
 	UndoManager::instance()->setUndoEnabled(true);
Index: scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp	(revision 14167)
+++ scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp	(revision 14168)
@@ -1182,9 +1182,21 @@
 				docu.writeAttribute("GRSTARTY", item->GrStartY);
 				docu.writeAttribute("GRENDX", item->GrEndX);
 				docu.writeAttribute("GRENDY", item->GrEndY);
-				docu.writeAttribute("GRNAME", item->gradient());
 			}
 		}
+		if (!item->gradient().isEmpty())
+			docu.writeAttribute("GRNAME", item->gradient());
+		if (!item->strokePattern().isEmpty())
+		{
+			docu.writeAttribute("patternS", item->strokePattern());
+			double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+			item->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+			docu.writeAttribute("pScaleXS", patternScaleX);
+			docu.writeAttribute("pScaleYS", patternScaleY);
+			docu.writeAttribute("pOffsetXS", patternOffsetX);
+			docu.writeAttribute("pOffsetYS", patternOffsetY);
+			docu.writeAttribute("pRotationS", patternRotation);
+		}
 		if (item->itemText.defaultStyle().hasParent())
 			docu.writeAttribute("PSTYLE", item->itemText.defaultStyle().parent());
 		if (! item->itemText.defaultStyle().isInhAlignment())
@@ -1241,7 +1253,7 @@
 				docu.writeAttribute("Fill", tabCh);
 			}
 		}
-		if ((item->GrType > 0) && (item->GrType != 8))
+		if (((item->GrType > 0) && (item->GrType != 8)) && (item->gradient().isEmpty()))
 		{
 			QList<VColorStop*> cstops = item->fill_gradient.colorStops();
 			for (uint cst = 0; cst < item->fill_gradient.Stops(); ++cst)
Index: scribus/plugins/fileloader/scribus150format/scribus150format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus150format/scribus150format.cpp	(revision 14167)
+++ scribus/plugins/fileloader/scribus150format/scribus150format.cpp	(revision 14168)
@@ -2766,7 +2766,7 @@
 				currItem->setGradient(GrName);
 		}
 	}
-	if ((currItem->GrType != 0) && (currItem->GrType != 8))
+	if (((currItem->GrType != 0) && (currItem->GrType != 8)) && (currItem->gradient().isEmpty()))
 	{
 		currItem->fill_gradient.clearStops();
 		if ((!GrColor.isEmpty()) && (!GrColor2.isEmpty()))
@@ -2792,6 +2792,13 @@
 		}
 //		currItem->updateGradientVectors();
 	}
+	currItem->setStrokePattern( attrs.valueAsString("patternS", "") );
+	double patternScaleX   = attrs.valueAsDouble("pScaleXS", 100.0);
+	double patternScaleY   = attrs.valueAsDouble("pScaleYS", 100.0);
+	double patternOffsetX  = attrs.valueAsDouble("pOffsetXS", 0.0);
+	double patternOffsetY  = attrs.valueAsDouble("pOffsetYS", 0.0);
+	double patternRotation = attrs.valueAsDouble("pRotationS", 0.0);
+	currItem->setStrokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
 	//currItem->setRedrawBounding();
 	//currItem->OwnPage = view->OnPage(currItem);
 	UndoManager::instance()->setUndoEnabled(true);
Index: scribus/plugins/fileloader/oodraw/oodrawimp.cpp
===================================================================
--- scribus/plugins/fileloader/oodraw/oodrawimp.cpp	(revision 14167)
+++ scribus/plugins/fileloader/oodraw/oodrawimp.cpp	(revision 14168)
@@ -1164,7 +1164,7 @@
 				{
 					if ((gradientAngle == 0) || (gradientAngle == 180))
 					{
-						item->GrType = 2;
+						item->GrType = 6;
 						item->GrStartX = item->width() / 2.0;
 						item->GrStartY = 0;
 						item->GrEndX = item->width() / 2.0;
@@ -1172,7 +1172,7 @@
 					}
 					else if ((gradientAngle == 90) || (gradientAngle == 270))
 					{
-						item->GrType = 1;
+						item->GrType = 6;
 						item->GrStartX = 0;
 						item->GrStartY = item->height() / 2.0;
 						item->GrEndX = item->width();
Index: scribus/plugins/fileloader/scribus134format/scribus134format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus134format/scribus134format.cpp	(revision 14167)
+++ scribus/plugins/fileloader/scribus134format/scribus134format.cpp	(revision 14168)
@@ -2834,6 +2834,20 @@
 		}
 //		currItem->updateGradientVectors();
 	}
+	switch (currItem->GrType)
+	{
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+			currItem->GrType = 6;
+			break;
+		case 5:
+			currItem->GrType = 7;
+			break;
+		default:
+			break;
+	}
 	//currItem->setRedrawBounding();
 	//currItem->OwnPage = view->OnPage(currItem);
 	UndoManager::instance()->setUndoEnabled(true);
Index: scribus/pslib.cpp
===================================================================
--- scribus/pslib.cpp	(revision 14167)
+++ scribus/pslib.cpp	(revision 14168)
@@ -2124,18 +2124,23 @@
 				if (!imageOk) return false;
 			}
 			PS_restore();
-			if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty())) && (!c->isTableItem))
+			if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty())) && (!c->isTableItem))
 			{
 				if (c->NamedLStyle.isEmpty()) // && (c->lineWidth() != 0.0))
 				{
-					SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
-					PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
 					PS_setlinewidth(c->lineWidth());
 					PS_setcapjoin(c->PLineEnd, c->PLineJoin);
 					PS_setdash(c->PLineArt, c->DashOffset, c->DashValues);
 					SetClipPath(&c->PoLine);
 					PS_closepath();
-					putColor(c->lineColor(), c->lineShade(), false);
+					if (!c->strokePattern().isEmpty())
+						HandleStrokePattern(c);
+					else
+					{
+						SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
+						PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
+						putColor(c->lineColor(), c->lineShade(), false);
+					}
 				}
 				else
 				{
@@ -2208,10 +2213,8 @@
 				PS_scale(1, -1);
 			}
 			setTextSt(Doc, c, gcr, PNr-1, a, sep, farb, ic, master);
-			if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty())) && (!c->isTableItem))
+			if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty())) && (!c->isTableItem))
 			{
-				SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
-				PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
 				PS_setlinewidth(c->lineWidth());
 				PS_setcapjoin(c->PLineEnd, c->PLineJoin);
 				PS_setdash(c->PLineArt, c->DashOffset, c->DashValues);
@@ -2219,7 +2222,14 @@
 				{
 					SetClipPath(&c->PoLine);
 					PS_closepath();
-					putColor(c->lineColor(), c->lineShade(), false);
+					if (!c->strokePattern().isEmpty())
+						HandleStrokePattern(c);
+					else
+					{
+						SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
+						PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
+						putColor(c->lineColor(), c->lineShade(), false);
+					}
 				}
 				else
 				{
@@ -2244,10 +2254,16 @@
 		case PageItem::Line:
 			if (c->NamedLStyle.isEmpty()) // && (c->lineWidth() != 0.0))
 			{
-				if (c->lineColor() != CommonStrings::None)
+				if (!c->strokePattern().isEmpty())
 				{
 					PS_moveto(0, 0);
 					PS_lineto(c->width(), 0);
+					HandleStrokePattern(c);
+				}
+				else if (c->lineColor() != CommonStrings::None)
+				{
+					PS_moveto(0, 0);
+					PS_lineto(c->width(), 0);
 					putColor(c->lineColor(), c->lineShade(), false);
 				}
 			}
@@ -2299,16 +2315,16 @@
 				else
 					putColor(c->fillColor(), c->fillShade(), true);
 			}
-			if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()))
+			if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()))
 			{
 				if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
 				{
-					if (c->lineColor() != CommonStrings::None)
-					{
-						SetClipPath(&c->PoLine);
-						PS_closepath();
+					SetClipPath(&c->PoLine);
+					PS_closepath();
+					if (!c->strokePattern().isEmpty())
+						HandleStrokePattern(c);
+					else if (c->lineColor() != CommonStrings::None)
 						putColor(c->lineColor(), c->lineShade(), false);
-					}
 				}
 				else
 				{
@@ -2341,15 +2357,15 @@
 					putColor(c->fillColor(), c->fillShade(), true);
 				PS_newpath();
 			}
-			if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()))
+			if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()))
 			{
 				if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
 				{
-					if (c->lineColor() != CommonStrings::None)
-					{
-						SetClipPath(&c->PoLine, false);
+					SetClipPath(&c->PoLine, false);
+					if (!c->strokePattern().isEmpty())
+						HandleStrokePattern(c);
+					else if (c->lineColor() != CommonStrings::None)
 						putColor(c->lineColor(), c->lineShade(), false);
-					}
 				}
 				else
 				{
@@ -2412,11 +2428,11 @@
 					PS_save();
 					if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
 					{
-						if (c->lineColor() != CommonStrings::None)
-						{
-							SetClipPath(&c->PoLine, false);
+						SetClipPath(&c->PoLine, false);
+						if (!c->strokePattern().isEmpty())
+							HandleStrokePattern(c);
+						else if (c->lineColor() != CommonStrings::None)
 							putColor(c->lineColor(), c->lineShade(), false);
-						}
 					}
 					else
 					{
@@ -3146,18 +3162,25 @@
 					PS_scale(1, -1);
 				}
 				setTextSt(Doc, ite, gcr, PNr, mPage, sep, farb, ic, true);
-				if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty())) && (!ite->isTableItem))
+				if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty())) && (!ite->isTableItem))
 				{
 					if (ite->NamedLStyle.isEmpty()) // && (ite->lineWidth() != 0.0))
 					{
-						SetColor(ite->lineColor(), ite->lineShade(), &h, &s, &v, &k, gcr);
-						PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
 						PS_setlinewidth(ite->lineWidth());
 						PS_setcapjoin(ite->PLineEnd, ite->PLineJoin);
 						PS_setdash(ite->PLineArt, ite->DashOffset, ite->DashValues);
 						SetClipPath(&ite->PoLine);
 						PS_closepath();
-						putColor(ite->lineColor(), ite->lineShade(), false);
+						if (!ite->strokePattern().isEmpty())
+						{
+							HandleStrokePattern(ite);
+						}
+						else
+						{
+							SetColor(ite->lineColor(), ite->lineShade(), &h, &s, &v, &k, gcr);
+							PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
+							putColor(ite->lineColor(), ite->lineShade(), false);
+						}
 					}
 					else
 					{
@@ -3397,6 +3420,23 @@
 	return success;
 }
 
+void PSLib::HandleStrokePattern(PageItem *c)
+{
+	ScPattern *pat;
+	QTransform patternMatrix;
+	double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+	pat = &m_Doc->docPatterns[c->strokePattern()];
+	uint patHash = qHash(c->strokePattern());
+	c->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+	patternMatrix.translate(-c->lineWidth() / 2.0, c->lineWidth() / 2.0);
+	patternMatrix.translate(patternOffsetX, -patternOffsetY);
+	patternMatrix.rotate(-patternRotation);
+	patternMatrix.scale(pat->scaleX, pat->scaleY);
+	patternMatrix.scale(patternScaleX / 100.0 , patternScaleY / 100.0);
+	PutStream("Pattern"+QString::number(patHash)+" ["+ToStr(patternMatrix.m11())+" "+ToStr(patternMatrix.m12())+" "+ToStr(patternMatrix.m21())+" "+ToStr(patternMatrix.m22())+" "+ToStr(patternMatrix.dx())+" "+ToStr(patternMatrix.dy())+"] makepattern setpattern\n");
+	PutStream("stroke\n");
+}
+
 void PSLib::HandleGradient(PageItem *c, double w, double h, bool gcr)
 {
 	int ch,cs,cv,ck;
@@ -3410,44 +3450,6 @@
 	QList<VColorStop*> cstops = c->fill_gradient.colorStops();
 	switch (c->GrType)
 	{
-/*		case 1:
-			StartX = 0;
-			StartY = h / 2.0;
-			EndX = w;
-			EndY = h / 2.0;
-			break;
-		case 2:
-			StartX = w / 2.0;
-			StartY = 0;
-			EndX = w / 2.0;
-			EndY = h;
-			break;
-		case 3:
-			StartX = 0;
-			StartY = 0;
-			EndX = w;
-			EndY = h;
-			break;
-		case 4:
-			StartX = 0;
-			StartY = h;
-			EndX = w;
-			EndY = 0;
-			break;
-		case 5:
-			StartX = w / 2.0;
-			StartY = h / 2.0;
-			if (w >= h)
-			{
-				EndX = w;
-				EndY = h / 2.0;
-			}
-			else
-			{
-				EndX = w / 2.0;
-				EndY = h;
-			}
-			break; */
 		case 1:
 		case 2:
 		case 3:
@@ -3556,8 +3558,25 @@
 	arrow.map(arrowTrans);
 	if (ite->NamedLStyle.isEmpty())
 	{
-		if (ite->lineColor() != CommonStrings::None)
+		if (!ite->strokePattern().isEmpty())
 		{
+			PS_newpath();
+			SetClipPath(&arrow);
+			PS_closepath();
+			QTransform patternMatrix;
+			double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+			ScPattern *pat = &m_Doc->docPatterns[ite->strokePattern()];
+			uint patHash = qHash(ite->strokePattern());
+			ite->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+			patternMatrix.translate(patternOffsetX, -patternOffsetY);
+			patternMatrix.rotate(-patternRotation);
+			patternMatrix.scale(pat->scaleX, pat->scaleY);
+			patternMatrix.scale(patternScaleX / 100.0 , patternScaleY / 100.0);
+			PutStream("Pattern"+QString::number(patHash)+" ["+ToStr(patternMatrix.m11())+" "+ToStr(patternMatrix.m12())+" "+ToStr(patternMatrix.m21())+" "+ToStr(patternMatrix.m22())+" "+ToStr(patternMatrix.dx())+" "+ToStr(patternMatrix.dy())+"] makepattern setpattern\n");
+			PutStream("fill\n");
+		}
+		else if (ite->lineColor() != CommonStrings::None)
+		{
 			SetColor(ite->lineColor(), ite->lineShade(), &h, &s, &v, &k, gcr);
 			PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
 			PS_newpath();
Index: scribus/pageitem_desaxe.cpp
===================================================================
--- scribus/pageitem_desaxe.cpp	(revision 14167)
+++ scribus/pageitem_desaxe.cpp	(revision 14168)
@@ -254,6 +254,20 @@
 			handler.end("PSDLayer");
 		}
 	}
+	if (!strokePattern().isEmpty())
+	{
+		Xml_attr patt;
+		patt.insert("patternS", strokePattern());
+		double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
+		strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+		patt.insert("pScaleXS", toXMLString(patternScaleX));
+		patt.insert("pScaleYS", toXMLString(patternScaleY));
+		patt.insert("pOffsetXS", toXMLString(patternOffsetX));
+		patt.insert("pOffsetYS", toXMLString(patternOffsetY));
+		patt.insert("pRotationS", toXMLString(patternRotation));
+		handler.begin("PatternStroke", patt);
+		handler.end("PatternStroke");
+	}
 	if (gradientType() != 0)
 	{
 		if (gradientType() == 8)
@@ -530,8 +544,6 @@
 		double patternOffsetX = parseDouble(attr["pOffsetX"]);
 		double patternOffsetY = parseDouble(attr["pOffsetY"]);
 		double patternRotation = parseDouble(attr["pRotation"]);
-//		qDebug() << QString("pageitem_desaxe: pattern %6: *(%1,%2) +(%3,%4) °%5").arg(patternScaleX).arg(patternScaleY).arg(patternOffsetX).arg(patternOffsetY).arg(patternRotation).arg(attr["pattern"]);
-
 		item->setPattern(attr["pattern"]);
 		item->setPatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
 	}
@@ -540,8 +552,27 @@
 class Pattern : public MakeAction<Pattern_body>
 {};
 
+class PatternStroke_body : public Action_body
+{
+	void begin (const Xml_string& tagName, Xml_attr attr)
+	{
+		PageItem* item = this->dig->top<PageItem>();
+		
+		double patternScaleX = parseDouble(attr["pScaleXS"]);
+		double patternScaleY = parseDouble(attr["pScaleYS"]);
+		double patternOffsetX = parseDouble(attr["pOffsetXS"]);
+		double patternOffsetY = parseDouble(attr["pOffsetYS"]);
+		double patternRotation = parseDouble(attr["pRotationS"]);
+		item->setStrokePattern(attr["patternS"]);
+		item->setStrokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
+	}
+};
 
+class PatternStroke : public MakeAction<PatternStroke_body>
+{};
 
+
+
 class ImageEffectsAndLayers_body : public Action_body
 {
 	void begin (const Xml_string& tagName, Xml_attr attr)
@@ -796,6 +827,7 @@
 	ruleset.addRule(itemPrefix, SetAttributeWithConversion<PageItem,bool>( & PageItem::setHasBottomLine, "BottomLine", &parseBool ));
 	
 	ruleset.addRule(Digester::concat(itemPrefix, "Pattern"), Pattern()); 
+	ruleset.addRule(Digester::concat(itemPrefix, "PatternStroke"), PatternStroke()); 
 	
 	Gradient gradient;
 	Xml_string gradientPrefix(Digester::concat(itemPrefix, "Gradient"));
Index: scribus/scpainter.h
===================================================================
--- scribus/scpainter.h	(revision 14167)
+++ scribus/scpainter.h	(revision 14168)
@@ -68,6 +68,7 @@
 	virtual void setFillRule( bool fillRule );
 	virtual bool fillRule() { return m_fillRule; }
 	virtual void setFillMode( int fill );
+	virtual void setStrokeMode( int stroke );
 	virtual void setGradient( VGradient::VGradientType mode, FPoint orig, FPoint vec, FPoint foc = FPoint(0,0));
 	virtual void setPattern(ScPattern *pattern, double scaleX, double scaleY, double offsetX, double offsetY, double rotation);
 	virtual void setClipPath();
@@ -157,6 +158,7 @@
 	QColor m_stroke;
 	double stroke_trans;
 	double LineWidth;
+	int strokeMode;				// 0 = none, 1 = solid, 2 = gradient 3 = pattern
 
 	/*! \brief Line End Style */
 	Qt::PenCapStyle PLineEnd;




More information about the scribus-commit mailing list