From 286a3d119ec95b235b09935296450ec36e640aeb Mon Sep 17 00:00:00 2001
From: Mateusz Piekos <mateuszpiekos@gmail.com>
Date: Thu, 21 Jun 2012 20:05:56 +0200
Subject: Added parsing and serialization of freehand path element


diff --git a/Swift/QtUI/Whiteboard/FreehandLineItem.cpp b/Swift/QtUI/Whiteboard/FreehandLineItem.cpp
index af8e827..bd53843 100644
--- a/Swift/QtUI/Whiteboard/FreehandLineItem.cpp
+++ b/Swift/QtUI/Whiteboard/FreehandLineItem.cpp
@@ -86,7 +86,7 @@ namespace Swift {
 		return pen_;
 	}
 
-	QVector<QPointF> FreehandLineItem::points() const {
+	const QVector<QPointF>& FreehandLineItem::points() const {
 		return points_;
 	}
 
diff --git a/Swift/QtUI/Whiteboard/FreehandLineItem.h b/Swift/QtUI/Whiteboard/FreehandLineItem.h
index e995cab..b0be36b 100644
--- a/Swift/QtUI/Whiteboard/FreehandLineItem.h
+++ b/Swift/QtUI/Whiteboard/FreehandLineItem.h
@@ -24,7 +24,7 @@ namespace Swift {
 		bool collidesWithPath(const QPainterPath& path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
 		void setPen(const QPen& pen);
 		QPen pen() const;
-		QVector<QPointF> points() const;
+		const QVector<QPointF>& points() const;
 		int type() const;
 
 	private:
diff --git a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
index 612e467..0a1afe3 100644
--- a/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
+++ b/Swift/QtUI/Whiteboard/QtWhiteboardWindow.cpp
@@ -245,15 +245,21 @@ namespace Swift {
 		}
 		FreehandLineItem* freehandLineItem = qgraphicsitem_cast<FreehandLineItem*>(item);
 		if (freehandLineItem != 0) {
-			QVector<QPointF> points = freehandLineItem->points();
-			QVector<QPointF>::iterator it;
-			std::stringstream stream;
-			stream << "F";
-			QPoint point;
-			for (it = points.begin(); it != points.end(); ++it) {
-				stream << it->x() << "," << it->y() << ",";
+			WhiteboardFreehandPathElement::ref element = boost::make_shared<WhiteboardFreehandPathElement>();
+			QColor color = freehandLineItem->pen().color();
+			std::vector<std::pair<int, int> > points;
+			QVector<QPointF>::const_iterator it = freehandLineItem->points().constBegin();
+			for ( ; it != freehandLineItem->points().constEnd(); ++it) {
+				points.push_back(std::pair<int, int>(it->x(), it->y()));
 			}
-			stream >> serialized;
+
+			element->setColor(Color(color.red(), color.green(), color.blue(), color.alpha()));
+			element->setPenWidth(freehandLineItem->pen().width());
+			element->setPoints(points);
+
+			element->setID(freehandLineItem->data(0).toString().toStdString());
+			whiteboardSession_->sendElement(element);
+
 		}
 	}
 
diff --git a/Swift/QtUI/Whiteboard/WhiteboardElementDrawingVisitor.h b/Swift/QtUI/Whiteboard/WhiteboardElementDrawingVisitor.h
index a1715bc..3b144cc 100644
--- a/Swift/QtUI/Whiteboard/WhiteboardElementDrawingVisitor.h
+++ b/Swift/QtUI/Whiteboard/WhiteboardElementDrawingVisitor.h
@@ -8,6 +8,7 @@
 
 #include <Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h>
 #include <Swiften/Whiteboard/Elements/WhiteboardLineElement.h>
+#include <Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h>
 #include <Swift/QtUI/Whiteboard/GView.h>
 
 namespace Swift {
@@ -15,16 +16,33 @@ namespace Swift {
 	public:
 		WhiteboardElementDrawingVisitor(GView* graphicsView) : graphicsView_(graphicsView) {}
 
-		void visit(const WhiteboardLineElement* element) {
-			QGraphicsLineItem *item = new QGraphicsLineItem(element->x1(), element->y1(), element->x2(), element->y2());
+		void visit(WhiteboardLineElement& element) {
+			QGraphicsLineItem *item = new QGraphicsLineItem(element.x1(), element.y1(), element.x2(), element.y2());
 			QPen pen;
-			Color color = element->getColor();
+			Color color = element.getColor();
 			pen.setColor(QColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()));
-			pen.setWidth(element->getPenWidth());
+			pen.setWidth(element.getPenWidth());
 			item->setPen(pen);
 			graphicsView_->scene()->addItem(item);
 		}
 
+		void visit(WhiteboardFreehandPathElement& element) {
+			FreehandLineItem *item = new FreehandLineItem;
+			QPen pen;
+			Color color = element.getColor();
+			pen.setColor(QColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()));
+			pen.setWidth(element.getPenWidth());
+			item->setPen(pen);
+
+			std::vector<std::pair<int, int> >::const_iterator it = element.getPoints().begin();
+			item->setStartPoint(QPointF(it->first, it->second));
+			for (++it; it != element.getPoints().end(); ++it) {
+				item->lineTo(QPointF(it->first, it->second));
+			}
+
+			graphicsView_->scene()->addItem(item);
+		}
+
 	private:
 		GView* graphicsView_;
 	};
diff --git a/Swiften/Base/String.cpp b/Swiften/Base/String.cpp
index 7ddf614..242b8e5 100644
--- a/Swiften/Base/String.cpp
+++ b/Swiften/Base/String.cpp
@@ -6,6 +6,8 @@
 
 #include <cassert>
 #include <algorithm>
+#include <sstream>
+#include <iomanip>
 
 #include <Swiften/Base/String.h>
 
@@ -95,4 +97,20 @@ std::vector<std::string> String::split(const std::string& s, char c) {
 	return result;
 }
 
+std::string String::convertIntToHexString(int h) {
+	std::stringstream ss;
+	ss << std::setbase(16);
+	ss << h;
+	return ss.str();
+}
+
+int String::convertHexStringToInt(const std::string& s) {
+	std::stringstream ss;
+	int h;
+	ss << std::setbase(16);
+	ss << s;
+	ss >> h;
+	return h;
+}
+
 }
diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h
index db6c28b..1dd303f 100644
--- a/Swiften/Base/String.h
+++ b/Swiften/Base/String.h
@@ -27,6 +27,9 @@ namespace Swift {
 			inline bool endsWith(const std::string& s, char c) { 
 				return s.size() > 0 && s[s.size()-1] == c; 
 			}
+
+			std::string convertIntToHexString(int h);
+			int convertHexStringToInt(const std::string& s);
 	};
 
 	class makeString {
diff --git a/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
index d0fa9f9..7182a8c 100644
--- a/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
+++ b/Swiften/Parser/PayloadParsers/WhiteboardParser.cpp
@@ -6,9 +6,11 @@
 
 #include <Swiften/Parser/PayloadParsers/WhiteboardParser.h>
 #include <Swiften/Whiteboard/Elements/WhiteboardLineElement.h>
+#include <Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h>
 #include <Swiften/Whiteboard/Elements/Color.h>
 #include <boost/optional.hpp>
 #include <boost/smart_ptr/make_shared.hpp>
+#include <boost/lexical_cast.hpp>
 
 namespace Swift {
 	WhiteboardParser::WhiteboardParser() : level_(0) {
@@ -19,24 +21,93 @@ namespace Swift {
 			getPayloadInternal()->setType(stringToType(attributes.getAttributeValue("type").get_value_or("")));
 		} else if (level_ == 1) {
 			if (element == "line") {
-				int x1 = std::atoi(attributes.getAttributeValue("x1").get_value_or("0").c_str());
-				int y1 = std::atoi(attributes.getAttributeValue("y1").get_value_or("0").c_str());
-				int x2 = std::atoi(attributes.getAttributeValue("x2").get_value_or("0").c_str());
-				int y2 = std::atoi(attributes.getAttributeValue("y2").get_value_or("0").c_str());
+				int x1 = 0;
+				int y1 = 0;
+				int x2 = 0;
+				int y2 = 0;
+				try {
+					x1 = boost::lexical_cast<int>(attributes.getAttributeValue("x1").get_value_or("0"));
+					y1 = boost::lexical_cast<int>(attributes.getAttributeValue("y1").get_value_or("0"));
+					x2 = boost::lexical_cast<int>(attributes.getAttributeValue("x2").get_value_or("0"));
+					y2 = boost::lexical_cast<int>(attributes.getAttributeValue("y2").get_value_or("0"));
+				} catch (boost::bad_lexical_cast&) {
+				}
 				WhiteboardLineElement::ref whiteboardElement = boost::make_shared<WhiteboardLineElement>(x1, y1, x2, y2);
-				Color color(attributes.getAttributeValue("stroke").get_value_or("#00000"));
+				Color color(attributes.getAttributeValue("stroke").get_value_or("#000000"));
 
 				std::string opacity = attributes.getAttributeValue("opacity").get_value_or("1");
 				if (opacity.find('.') != std::string::npos) {
 					opacity = opacity.substr(opacity.find('.')+1, 2);
-					color.setAlpha(std::atoi(opacity.c_str())*255/100);
+					try {
+						color.setAlpha(boost::lexical_cast<int>(opacity)*255/100);
+					} catch (boost::bad_lexical_cast&) {
+					}
 				} 
-
 				whiteboardElement->setColor(color);
 
-				int penWidth = std::atoi(attributes.getAttributeValue("stroke-width").get_value_or("1").c_str());
+				int penWidth = 1;
+				try {
+					penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1"));
+				} catch (boost::bad_lexical_cast&) {
+				}
+				whiteboardElement->setPenWidth(penWidth);
+
+				getPayloadInternal()->setElement(whiteboardElement);
+			} else if (element == "path") {
+				WhiteboardFreehandPathElement::ref whiteboardElement = boost::make_shared<WhiteboardFreehandPathElement>();
+				std::string pathData = attributes.getAttributeValue("d").get_value_or("");
+				std::vector<std::pair<int, int> > points;
+				if (pathData[0] == 'M') {
+					int pos = 1;
+					int npos;
+					int x, y;
+					if (pathData[pos] == ' ') {
+						pos++;
+					}
+					try {
+						npos = pathData.find(' ', pos);
+						x = boost::lexical_cast<int>(pathData.substr(pos, npos-pos));
+						pos = npos+1;
+						npos = pathData.find('L', pos);
+						y = boost::lexical_cast<int>(pathData.substr(pos, npos-pos));
+						pos = npos+1;
+						if (pathData[pos] == ' ') {
+							pos++;
+						}
+						points.push_back(std::pair<int, int>(x, y));
+						while (pos < pathData.size()) {
+							npos = pathData.find(' ', pos);
+							x = boost::lexical_cast<int>(pathData.substr(pos, npos-pos));
+							pos = npos+1;
+							npos = pathData.find(' ', pos);
+							y = boost::lexical_cast<int>(pathData.substr(pos, npos-pos));
+							pos = npos+1;
+							points.push_back(std::pair<int, int>(x, y));
+						}
+					} catch (boost::bad_lexical_cast&) {
+					}
+				}
+				whiteboardElement->setPoints(points);
+
+				int penWidth = 1;
+				try {
+					penWidth = boost::lexical_cast<int>(attributes.getAttributeValue("stroke-width").get_value_or("1"));
+				} catch (boost::bad_lexical_cast&) {
+				}
 				whiteboardElement->setPenWidth(penWidth);
 
+				Color color(attributes.getAttributeValue("stroke").get_value_or("#000000"));
+
+				std::string opacity = attributes.getAttributeValue("opacity").get_value_or("1");
+				if (opacity.find('.') != std::string::npos) {
+					opacity = opacity.substr(opacity.find('.')+1, 2);
+					try {
+						color.setAlpha(boost::lexical_cast<int>(opacity)*255/100);
+					} catch (boost::bad_lexical_cast&) {
+					}
+				} 
+				whiteboardElement->setColor(color);
+
 				getPayloadInternal()->setElement(whiteboardElement);
 			}
 		}
diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp
index f02791c..b5a4c49 100644
--- a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.cpp
@@ -7,24 +7,54 @@
 #include <Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h>
 
 #include <boost/smart_ptr/make_shared.hpp>
+#include <boost/lexical_cast.hpp>
 #include <Swiften/Serializer/XML/XMLTextNode.h>
 
 namespace Swift {
-	void WhiteboardElementSerializingVisitor::visit(const WhiteboardLineElement* line) {
+	void WhiteboardElementSerializingVisitor::visit(WhiteboardLineElement& line) {
 		element = boost::make_shared<XMLElement>("line");
-		element->setAttribute("x1", intToStr(line->x1()));
-		element->setAttribute("y1", intToStr(line->y1()));
-		element->setAttribute("x2", intToStr(line->x2()));
-		element->setAttribute("y2", intToStr(line->y2()));
-		element->setAttribute("id", line->getID());
-		element->setAttribute("stroke", line->getColor().toHex());
-		element->setAttribute("stroke-width", intToStr(line->getPenWidth()));
-		int alpha = line->getColor().getAlpha();
-		int opacity = 100*alpha/254;
-		if (opacity == 100) {
-			element->setAttribute("opacity", "1");
-		} else {
-			element->setAttribute("opacity", "."+intToStr(opacity));
+		try {
+			element->setAttribute("x1", boost::lexical_cast<std::string>(line.x1()));
+			element->setAttribute("y1", boost::lexical_cast<std::string>(line.y1()));
+			element->setAttribute("x2", boost::lexical_cast<std::string>(line.x2()));
+			element->setAttribute("y2", boost::lexical_cast<std::string>(line.y2()));
+			element->setAttribute("id", line.getID());
+			element->setAttribute("stroke", line.getColor().toHex());
+			element->setAttribute("stroke-width", boost::lexical_cast<std::string>(line.getPenWidth()));
+			int alpha = line.getColor().getAlpha();
+			int opacity = 100*alpha/254;
+			if (opacity == 100) {
+				element->setAttribute("opacity", "1");
+			} else {
+				element->setAttribute("opacity", "."+boost::lexical_cast<std::string>(opacity));
+			}
+		} catch (boost::bad_lexical_cast&) {
+		}
+	}
+
+	void WhiteboardElementSerializingVisitor::visit(WhiteboardFreehandPathElement& path) {
+		element = boost::make_shared<XMLElement>("path");
+		element->setAttribute("id", path.getID());
+		element->setAttribute("stroke", path.getColor().toHex());
+		try {
+			element->setAttribute("stroke-width", boost::lexical_cast<std::string>(path.getPenWidth()));
+			int alpha = path.getColor().getAlpha();
+			int opacity = 100*alpha/254;
+			if (opacity == 100) {
+				element->setAttribute("opacity", "1");
+			} else {
+				element->setAttribute("opacity", "."+boost::lexical_cast<std::string>(opacity));
+			}
+			std::string pathData;
+			if (path.getPoints().size() != 0) {
+				std::vector<std::pair<int, int> >::const_iterator it = path.getPoints().begin();
+				pathData = "M"+boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+"L";
+				for (; it != path.getPoints().end(); ++it) {
+					pathData += boost::lexical_cast<std::string>(it->first)+" "+boost::lexical_cast<std::string>(it->second)+" ";
+				}
+			}
+			element->setAttribute("d", pathData);
+		} catch (boost::bad_lexical_cast&) {
 		}
 	}
 
diff --git a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
index 50cf252..25642d0 100644
--- a/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
+++ b/Swiften/Serializer/PayloadSerializers/WhiteboardSerializer.h
@@ -8,6 +8,7 @@
 
 #include <Swiften/Elements/WhiteboardPayload.h>
 #include <Swiften/Whiteboard/Elements/WhiteboardLineElement.h>
+#include <Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h>
 #include <Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h>
 #include <Swiften/Serializer/GenericPayloadSerializer.h>
 #include <Swiften/Serializer/XML/XMLElement.h>
@@ -15,7 +16,8 @@
 namespace Swift {
 	class WhiteboardElementSerializingVisitor : public WhiteboardElementVisitor {
 	public:
-		void visit(const WhiteboardLineElement* line);
+		void visit(WhiteboardLineElement& line);
+		void visit(WhiteboardFreehandPathElement& path);
 		XMLElement::ref getResult() const;
 
 	private:
diff --git a/Swiften/Whiteboard/Elements/Color.cpp b/Swiften/Whiteboard/Elements/Color.cpp
index b614a2a..51b8460 100644
--- a/Swiften/Whiteboard/Elements/Color.cpp
+++ b/Swiften/Whiteboard/Elements/Color.cpp
@@ -5,6 +5,7 @@
  */
 
 #include <Swiften/Whiteboard/Elements/Color.h>
+#include <Swiften/Base/String.cpp>
 #include <cstdio>
 #include <iomanip>
 #include <sstream>
@@ -18,39 +19,18 @@ namespace Swift {
 	}
 
 	Color::Color(const std::string& hex) : alpha_(255) {
-		if (hex.size() == 7) {
-			char temp[3];
-			hex.copy(temp, 2, 1);
-			temp[2] = 0;
-			std::sscanf(temp, "%x", &red_);
-			hex.copy(temp, 2, 3);
-			temp[2] = 0;
-			std::sscanf(temp, "%x", &green_);
-			hex.copy(temp, 2, 5);
-			temp[2] = 0;
-			std::sscanf(temp, "%x", &blue_);
-		}
+		int value = String::convertHexStringToInt(hex.substr(1));
+		red_ = (value >> 16)&0xFF;
+		green_ = (value >> 8)&0xFF;
+		blue_ = value&0xFF;
 	}
 
 	std::string Color::toHex() const {
-		std::string result = "#";
-		std::string hex;
-		hex = intToStr(red_, 16);
-		if (hex.size() == 1) {
-			result += "0";
-		}
-		result += hex;
-		hex = intToStr(green_, 16);
-		if (hex.size() == 1) {
-			result += "0";
-		}
-		result += hex;
-		hex = intToStr(blue_, 16);
-		if (hex.size() == 1) {
-			result += "0";
+		std::string value = String::convertIntToHexString((red_ << 16) + (green_ << 8) + blue_);
+		while (value.size() < 6) {
+			value.insert(0, "0");
 		}
-		result += hex;
-		return result;
+		return "#"+value;
 	}
 
 	int Color::getRed() const {
@@ -72,11 +52,4 @@ namespace Swift {
 	void Color::setAlpha(int alpha) {
 		alpha_ = alpha;
 	}
-
-	std::string Color::intToStr(int t, int base) const {
-		std::stringstream ss;
-		ss << std::setbase(base);
-		ss << t;
-		return ss.str();
-	}
 }
diff --git a/Swiften/Whiteboard/Elements/Color.h b/Swiften/Whiteboard/Elements/Color.h
index b7cca5a..7227eca 100644
--- a/Swiften/Whiteboard/Elements/Color.h
+++ b/Swiften/Whiteboard/Elements/Color.h
@@ -22,8 +22,6 @@ namespace Swift {
 		void setAlpha(int alpha);
 
 	private:
-		std::string intToStr(int t, int base = 10) const;
-
 		int red_, green_, blue_;
 		int alpha_;
 	};
diff --git a/Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h b/Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h
index b5fd546..d546e7f 100644
--- a/Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h
+++ b/Swiften/Whiteboard/Elements/WhiteboardElementVisitor.h
@@ -8,10 +8,12 @@
 
 namespace Swift {
 	class WhiteboardLineElement;
+	class WhiteboardFreehandPathElement;
 
 	class WhiteboardElementVisitor {
 	public:
 		virtual ~WhiteboardElementVisitor() {}
-		virtual void visit(const WhiteboardLineElement* /*element*/) = 0;
+		virtual void visit(WhiteboardLineElement& /*element*/) = 0;
+		virtual void visit(WhiteboardFreehandPathElement& /*element*/) = 0;
 	};
 }
diff --git a/Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h b/Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h
new file mode 100644
index 0000000..9b69dc4
--- /dev/null
+++ b/Swiften/Whiteboard/Elements/WhiteboardFreehandPathElement.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Whiteboard/Elements/WhiteboardElement.h>
+#include <Swiften/Whiteboard/Elements/Color.h>
+
+#include <vector>
+#include <utility>
+
+namespace Swift {
+	class WhiteboardFreehandPathElement : public WhiteboardElement {
+		typedef std::pair<int, int> Point;
+	public:
+		typedef boost::shared_ptr<WhiteboardFreehandPathElement> ref;
+	public:
+		WhiteboardFreehandPathElement() {
+		}
+
+		void setPoints(const std::vector<Point>& points) {
+			points_ = points;
+		}
+
+		const std::vector<Point>& getPoints() const {
+			return points_;
+		}
+
+		const Color& getColor() const {
+			return color_;
+		}
+
+		void setColor(const Color& color) {
+			color_ = color;
+		}
+
+		std::string getID() const {
+			return id_;
+		}
+
+		void setID(const std::string& id) {
+			id_ = id;
+		}
+
+		int getPenWidth() const {
+			return penWidth_;
+		}
+
+		void setPenWidth(const int penWidth) {
+			penWidth_ = penWidth;
+		}
+
+		void accept(WhiteboardElementVisitor& visitor) {
+			visitor.visit(*this);
+		}
+
+	private:
+
+		std::vector<Point> points_;
+		Color color_;
+		int penWidth_;
+		std::string id_;
+	};
+}
diff --git a/Swiften/Whiteboard/Elements/WhiteboardLineElement.h b/Swiften/Whiteboard/Elements/WhiteboardLineElement.h
index 0088189..20455b6 100644
--- a/Swiften/Whiteboard/Elements/WhiteboardLineElement.h
+++ b/Swiften/Whiteboard/Elements/WhiteboardLineElement.h
@@ -62,7 +62,7 @@ namespace Swift {
 		}
 
 		void accept(WhiteboardElementVisitor& visitor) {
-			visitor.visit(this);
+			visitor.visit(*this);
 		}
 
 	private:
-- 
cgit v0.10.2-6-g49f6