[qet] [1129] Introduction of classes, structs and enums related to inset templates.

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 1129
Author:   xavier
Date:     2010-12-19 19:08:08 +0100 (Sun, 19 Dec 2010)
Log Message:
-----------
Introduction of classes, structs and enums related to inset templates.

Modified Paths:
--------------
    branches/0.3/sources/qet.cpp
    branches/0.3/sources/qet.h

Added Paths:
-----------
    branches/0.3/sources/diagramcontext.cpp
    branches/0.3/sources/diagramcontext.h
    branches/0.3/sources/insetcell.h
    branches/0.3/sources/insettemplate.cpp
    branches/0.3/sources/insettemplate.h
    branches/0.3/sources/insettemplaterenderer.cpp
    branches/0.3/sources/insettemplaterenderer.h

Added: branches/0.3/sources/diagramcontext.cpp
===================================================================
--- branches/0.3/sources/diagramcontext.cpp	                        (rev 0)
+++ branches/0.3/sources/diagramcontext.cpp	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,65 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "diagramcontext.h"
+#include <QRegExp>
+
+/**
+	@return a list containing all the keys in the context object.
+*/
+QList<QString> DiagramContext::keys() const {
+	return(content_.keys());
+}
+
+/**
+	@param key string key
+	@return true if that key is known to the diagram context, false otherwise
+*/
+bool DiagramContext::contains(const QString &key) const {
+	return(content_.contains(key));
+}
+
+/**
+	@param key
+*/
+const QVariant DiagramContext::operator[](const QString &key) const {
+	return(content_[key]);
+}
+
+/**
+	@param key key to insert in the context - the key may only contain lowercase
+	letters and dashes
+	@see DiagramContext::keyIsAcceptable()
+	@param value value to insert in the context
+	@return true if the insertion succeeds, false otherwise
+*/
+bool DiagramContext::addValue(const QString &key, const QVariant &value) {
+	if (keyIsAcceptable(key)) {
+		content_.insert(key, value);
+		return(true);
+	}
+	return(false);
+}
+
+/**
+	@param key a key string
+	@return true if that key is acceptable, false otherwise
+*/
+bool DiagramContext::keyIsAcceptable(const QString &key) const {
+	static QRegExp re("^[a-z-]+$");
+	return(re.exactMatch(key));
+}

Added: branches/0.3/sources/diagramcontext.h
===================================================================
--- branches/0.3/sources/diagramcontext.h	                        (rev 0)
+++ branches/0.3/sources/diagramcontext.h	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,40 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef DIAGRAM_CONTEXT_H
+#define DIAGRAM_CONTEXT_H
+#include <QHash>
+#include <QString>
+#include <QVariant>
+/**
+	This class represents a diagram context, i.e. the data (a list of key/value
+	pairs) of a diagram at a given time. It is notably used by inset templates
+	to fetch the informations they need to do their rendering.
+*/
+class DiagramContext {
+	public:
+	QList<QString> keys() const;
+	bool contains(const QString &) const;
+	const QVariant operator[](const QString &) const;
+	bool addValue(const QString &, const QVariant &);
+	
+	private:
+	bool keyIsAcceptable(const QString &) const;
+	/// Diagram context data (key/value pairs)
+	QHash<QString, QVariant> content_;
+};
+#endif

Added: branches/0.3/sources/insetcell.h
===================================================================
--- branches/0.3/sources/insetcell.h	                        (rev 0)
+++ branches/0.3/sources/insetcell.h	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,41 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef INSET_CELL_H
+#define INSET_CELL_H
+/**
+	This class is a container for the various parameters of an inset cell
+	@see InsetColumnLength 
+*/
+class InsetCell {
+	public:
+	InsetCell();
+	QString toString() const;
+	bool is_null;
+	int num_row;
+	int num_col;
+	int row_span;
+	int col_span;
+	InsetCell *spanner_cell;
+	QString value_name;
+	QString value;
+	QString label;
+	bool display_label;
+	int alignment;
+	QString logo_reference;
+};
+#endif

Added: branches/0.3/sources/insettemplate.cpp
===================================================================
--- branches/0.3/sources/insettemplate.cpp	                        (rev 0)
+++ branches/0.3/sources/insettemplate.cpp	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,580 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "insettemplate.h"
+#include "qet.h"
+#include "qetapp.h"
+
+/**
+	Constructor
+	@param parent parent QObject
+*/
+InsetTemplate::InsetTemplate(QObject *parent) :
+	QObject(parent)
+{
+}
+
+/**
+	Destructor
+*/
+InsetTemplate::~InsetTemplate() {
+	loadLogos(QDomElement(), true);
+}
+
+/**
+	@param filepath A file path to read the template from.
+	@return true if the reading succeeds, false otherwise.
+*/
+bool InsetTemplate::loadFromXmlFile(const QString &filepath) {
+	// opens the file
+	QFile template_file(filepath);
+	if (!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+	    return(false);
+	}
+	
+	// parses its content as XML
+	bool xml_parsing = xml_description_.setContent(&template_file);
+	if (!xml_parsing) {
+		return(false);
+	}
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << filepath << "opened";
+#endif
+	return(loadFromXmlElement(xml_description_.documentElement()));
+}
+
+/**
+	@param xml_element An XML document to read the template from.
+	@return true if the reading succeeds, false otherwise.
+*/
+bool InsetTemplate::loadFromXmlElement(const QDomElement &xml_element) {
+	// we expect the XML element to be an <insettemplate>
+	if (xml_element.tagName() != "insettemplate") {
+		return(false);
+	}
+	
+	loadLogos(xml_element, true);
+	loadGrid(xml_element);
+	return(true);
+}
+
+/**
+	Imports the logos from a given XML inset template.
+	@param xml_element An XML element representing an inset template.
+	@param reset true to delete all previously known logos before, false
+	otherwise.
+	@return true if the reading succeeds, false otherwise.
+*/
+bool InsetTemplate::loadLogos(const QDomElement &xml_element, bool reset) {
+	if (reset) {
+		qDeleteAll(vector_logos_.begin(), vector_logos_.end());
+		vector_logos_.clear();
+		qDeleteAll(bitmap_logos_.begin(), bitmap_logos_.end());
+		bitmap_logos_.clear();
+	}
+	
+	// we look for //logos/logo elements
+	for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
+		if (n.isElement() && n.toElement().tagName() == "logos") {
+			for (QDomNode p = n.firstChild() ; !p.isNull() ; p = p.nextSibling()) {
+				if (p.isElement() && p.toElement().tagName() == "logo") {
+					loadLogo(p.toElement());
+				}
+			}
+		}
+	}
+	
+	return(true);
+}
+
+/**
+	Imports the logo from a given XML logo description.
+	@param xml_element An XML element representing a logo within an inset
+	template.
+	@return true if the reading succeeds, false otherwise.
+*/
+bool InsetTemplate::loadLogo(const QDomElement &xml_element) {
+	// we require a name
+	if (!xml_element.hasAttribute("name")) {
+		return(false);
+	}
+	QString logo_name    = xml_element.attribute("name");
+	QString logo_type    = xml_element.attribute("type", "png");
+	QString logo_storage = xml_element.attribute("storage", "base64");
+	
+	// Both QSvgRenderer and QPixmap read their data from a QByteArray, so
+	// we convert the available data to that format.
+	QByteArray logo_data;
+	if (logo_storage == "xml") {
+		// only svg uses xml storage
+		QDomNodeList svg_nodes = xml_element.elementsByTagName("svg");
+		if (svg_nodes.isEmpty()) {
+			return(false);
+		}
+		QDomElement svg_element = svg_nodes.at(0).toElement();
+		QTextStream xml_to_byte_array(&logo_data);
+		svg_element.save(xml_to_byte_array, 0);
+	} else if (logo_storage == "base64") {
+		logo_data = QByteArray::fromBase64(xml_element.text().toAscii());
+	} else {
+		return(false);
+	}
+	
+	// we can now create our image object from the byte array
+	if (logo_type == "svg") {
+		// SVG format is handled by the QSvgRenderer class
+		QSvgRenderer *svg = new QSvgRenderer(logo_data);
+		vector_logos_.insert(logo_name, svg);
+		
+		/*QSvgWidget *test_svgwidget = new QSvgWidget();
+		test_svgwidget -> load(logo_data);
+		test_svgwidget -> show();*/
+	} else {
+		// bitmap formats are handled by the QPixmap class
+		QPixmap *logo_pixmap = new QPixmap();
+		logo_pixmap -> loadFromData(logo_data);
+		if (!logo_pixmap -> width() || !logo_pixmap -> height()) {
+			return(false);
+		}
+		bitmap_logos_.insert(logo_name, logo_pixmap);
+		
+		/*QLabel *test_label = new QLabel();
+		test_label -> setPixmap(*logo_pixmap);
+		test_label -> show();*/
+	}
+	
+	return(true);
+}
+
+/**
+	Imports the grid from a given XML inset template.
+	@param xml_element An XML element representing an inset template.
+	@return true if the reading succeeds, false otherwise.
+*/
+bool InsetTemplate::loadGrid(const QDomElement &xml_element) {
+	// we parse the first available "grid" XML element
+	QDomElement grid_element;
+	for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
+		if (n.isElement() && n.toElement().tagName() == "grid") {
+			grid_element = n.toElement();
+			break;
+		}
+	}
+	
+	if (!grid_element.hasAttribute("rows") || !grid_element.hasAttribute("cols")) {
+		return(false);
+	}
+	
+	parseRows(grid_element.attribute("rows"));
+	parseColumns(grid_element.attribute("cols"));
+	loadCells(grid_element);
+	return(true);
+}
+
+/**
+	Parses the rows heights
+	@param rows_string A string describing the rows heights of the inset
+*/
+void InsetTemplate::parseRows(const QString &rows_string) {
+	rows_heights_.clear();
+	// parse the rows attribute: we expect a serie of absolute heights
+	QRegExp row_size_format("^([0-9]+)(?:px)?$", Qt::CaseInsensitive);
+	bool conv_ok;
+	
+	QStringList rows_descriptions = rows_string.split(QChar(';'), QString::SkipEmptyParts);
+	foreach (QString rows_description, rows_descriptions) {
+		if (row_size_format.exactMatch(rows_description)) {
+			int row_size = row_size_format.capturedTexts().at(1).toInt(&conv_ok);
+			if (conv_ok) rows_heights_ << row_size;
+		}
+	}
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << "Rows heights:" << rows_heights_;
+#endif
+}
+
+/**
+	Parses the columns widths
+	@param cols_string A string describing the columns widths of the inset
+*/
+void InsetTemplate::parseColumns(const QString &cols_string) {
+	columns_width_.clear();
+	// parse the cols attribute: we expect a serie of absolute or relative widths
+	QRegExp abs_col_size_format("^([0-9]+)(?:px)?$", Qt::CaseInsensitive);
+	QRegExp rel_col_size_format("^([rt])([0-9]+)%$", Qt::CaseInsensitive);
+	bool conv_ok;
+	
+	QStringList cols_descriptions = cols_string.split(QChar(';'), QString::SkipEmptyParts);
+	foreach (QString cols_description, cols_descriptions) {
+		if (abs_col_size_format.exactMatch(cols_description)) {
+			int col_size = abs_col_size_format.capturedTexts().at(1).toInt(&conv_ok);
+			if (conv_ok) columns_width_ << InsetColDimension(col_size, QET::Absolute);
+		} else if (rel_col_size_format.exactMatch(cols_description)) {
+			int col_size = rel_col_size_format.capturedTexts().at(2).toInt(&conv_ok);
+			QET::InsetColumnLength col_type = rel_col_size_format.capturedTexts().at(1) == "t" ? QET::RelativeToTotalLength : QET::RelativeToRemainingLength;
+			if (conv_ok) columns_width_ << InsetColDimension(col_size, col_type );
+		}
+	}
+#ifdef INSET_TEMPLATE_DEBUG
+	foreach (InsetColDimension icd, columns_width_) {
+		qDebug() << Q_FUNC_INFO << QString("%1 [%2]").arg(icd.value).arg(QET::insetColumnLengthToString(icd.type));
+	}
+#endif
+}
+
+/**
+	Analyze an XML element, looking for grid cells. The grid cells are checked
+	and stored in this object.
+	@param xml_element XML element to analyze
+*/
+bool InsetTemplate::loadCells(const QDomElement &xml_element) {
+	initCells();
+	// we are interested by the "logo" and "field" elements
+	QDomElement grid_element;
+	for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
+		if (!n.isElement()) continue;
+		QDomElement cell_element = n.toElement();
+		if (cell_element.tagName() == "field" || cell_element.tagName() == "logo") {
+			InsetCell *loaded_cell;
+			if (!checkCell(cell_element, &loaded_cell)) continue;
+			
+			if (cell_element.tagName() == "logo") {
+				if (cell_element.hasAttribute("resource") && !cell_element.attribute("resource").isEmpty()) {
+					loaded_cell -> logo_reference = cell_element.attribute("resource");
+				}
+			} else if (cell_element.tagName() == "field") {
+				if (cell_element.hasAttribute("name") && !cell_element.attribute("name").isEmpty()) {
+					loaded_cell -> value_name = cell_element.attribute("name");
+				}
+				if (cell_element.hasAttribute("value") && !cell_element.attribute("value").isEmpty()) {
+					loaded_cell -> value = cell_element.attribute("value");
+				}
+				if (cell_element.hasAttribute("label") && !cell_element.attribute("label").isEmpty()) {
+					loaded_cell -> label = cell_element.attribute("label");
+				}
+				if (cell_element.hasAttribute("displaylabel") && cell_element.attribute("displaylabel").compare("false", Qt::CaseInsensitive) == 0) {
+					loaded_cell -> display_label = false;
+				}
+				
+				// horiwontal and vertical alignments
+				loaded_cell -> alignment = 0;
+				
+				QString halignment = cell_element.attribute("align", "left");
+				if (halignment == "right") loaded_cell -> alignment |= Qt::AlignRight;
+				else if (halignment == "center") loaded_cell -> alignment |= Qt::AlignHCenter;
+				else loaded_cell -> alignment |= Qt::AlignLeft;
+				
+				QString valignment = cell_element.attribute("valign", "center");
+				if (halignment == "bottom") loaded_cell -> alignment |= Qt::AlignBottom;
+				else if (halignment == "top") loaded_cell -> alignment |= Qt::AlignTop;
+				else loaded_cell -> alignment |= Qt::AlignVCenter;
+			}
+		}
+	}
+	
+	return(true);
+}
+
+/**
+	@param xml_element XML element representing a cell, i.e. either an inset
+	logo or an inset field.
+	@param inset_cell_ptr Pointer to an InsetCell object pointer - if non-zero and if
+	this method returns true, will be filled with the created InsetCell
+	@return TRUE if the cell appears to be ok, FALSE otherwise
+*/
+bool InsetTemplate::checkCell(const QDomElement &xml_element, InsetCell **inset_cell_ptr) {
+	int col_count = columns_width_.count(), row_count = rows_heights_.count();
+	
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << "begin" << row_count << col_count;
+#endif
+	
+	int row_num, col_num, row_span, col_span;
+	bool has_row_span = false;
+	bool has_col_span = false;
+	row_num = col_num = -1;
+	row_span = col_span = 0;
+	
+	// parse the row and col attributes
+	if (!QET::attributeIsAnInteger(xml_element, "row", &row_num) || row_num < 0 || row_num >= row_count) {
+		return(false);
+	}
+	if (!QET::attributeIsAnInteger(xml_element, "col", &col_num) || col_num < 0 || col_num >= col_count) {
+		return(false);
+	}
+	
+	// check whether the target cell can be used or not
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << "cell access" << col_num << row_num;
+#endif
+	InsetCell *cell_ptr = &(cells_[col_num][row_num]);
+	if (!cell_ptr -> is_null || cell_ptr -> spanner_cell) {
+		return(false);
+	}
+	
+	// parse the rowspan and colspan attributes
+	if (QET::attributeIsAnInteger(xml_element, "rowspan", &row_span) && row_span > 0) {
+		if (row_num + row_span >= row_count) row_span = row_count - 1 - row_num;
+		has_row_span = true;
+	}
+	
+	if (QET::attributeIsAnInteger(xml_element, "colspan", &col_span) && col_span > 0) {
+		if (col_num + col_span >= col_count) col_span = col_count - 1 - col_num;
+		has_col_span = true;
+	}
+	
+	// check if we can span on the required area
+	if (has_row_span || has_col_span) {
+		for (int i = col_num ; i <= col_num + col_span ; ++ i) {
+			for (int j = row_num ; j <= row_num + row_span ; ++ j) {
+				if (i == col_num && j == row_num) continue;
+#ifdef INSET_TEMPLATE_DEBUG
+				qDebug() << Q_FUNC_INFO << "span check" << i << j;
+#endif
+				InsetCell *current_cell = &(cells_[i][j]);
+				if (!current_cell -> is_null || current_cell -> spanner_cell) {
+					return(false);
+				}
+			}
+		}
+	}
+	
+	// at this point, the cell is ok - we fill the adequate cells in the matrix
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << "cell writing";
+#endif
+	cell_ptr -> num_row = row_num;
+	cell_ptr -> num_col = col_num;
+	if (has_row_span) cell_ptr -> row_span = row_span;
+	if (has_col_span) cell_ptr -> col_span = col_span;
+	cell_ptr -> is_null = false;
+	if (inset_cell_ptr) *inset_cell_ptr = cell_ptr;
+	
+	if (has_row_span || has_col_span) {
+		for (int i = col_num ; i <= col_num + col_span ; ++ i) {
+			for (int j = row_num ; j <= row_num + row_span ; ++ j) {
+				if (i == col_num && j == row_num) continue;
+#ifdef INSET_TEMPLATE_DEBUG
+				qDebug() << Q_FUNC_INFO << "span cells writing" << i << j;
+#endif
+				InsetCell *current_cell = &(cells_[i][j]);
+				current_cell -> num_row = j;
+				current_cell -> num_col = i;
+				current_cell -> is_null = false;
+				current_cell -> spanner_cell = cell_ptr;
+			}
+		}
+	}
+	
+	return(true);
+}
+
+/**
+	Initializes the internal cells grid with the row and column counts.
+	Note that this method does nothing if one of the internal lists
+	columns_width_ and rows_heights_ is empty.
+*/
+void InsetTemplate::initCells() {
+	if (columns_width_.count() < 1 || rows_heights_.count() < 1) return;
+	
+	cells_.resize(columns_width_.count());
+	int row_count = rows_heights_.count();
+	for (int i = 0 ; i < columns_width_.count() ; ++ i) {
+		cells_[i].resize(row_count);
+		// ensure every cell is a null cell
+		for (int j = 0 ; j < row_count ; ++ j) {
+			cells_[i][j] = InsetCell();
+		}
+	}
+	
+#ifdef INSET_TEMPLATE_DEBUG
+	qDebug() << Q_FUNC_INFO << toString();
+#endif
+}
+
+/**
+	@return A string representing the inset template
+	@see InsetCell::toString()
+*/
+QString InsetTemplate::toString() const {
+	QString str = "\n";
+	for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
+		for (int i = 0 ; i < columns_width_.count() ; ++ i) {
+			str += cells_[i][j].toString() + "    ";
+		}
+		str += "\n";
+	}
+	return(str);
+}
+
+/**
+	@param total_width The total width of the inset to render
+	@return the list of the columns widths for this rendering
+*/
+QList<int> InsetTemplate::columnsWidth(int total_width) const {
+	if (total_width < 0) return(QList<int>());
+	
+	// we first iter to determine the absolute and total-width-related widths
+	QVector<int> final_widths(columns_width_.count());
+	int abs_widths_sum = 0;
+	
+	for (int i = 0 ; i < columns_width_.count() ; ++ i) {
+		InsetColDimension icd = columns_width_.at(i);
+		if (icd.type == QET::Absolute) {
+			abs_widths_sum += icd.value;
+			final_widths[i] = icd.value;
+		} else if (icd.type == QET::RelativeToTotalLength) {
+			int abs_value = int(total_width * icd.value / 100);
+			abs_widths_sum += abs_value;
+			final_widths[i] = abs_value;
+		}
+	}
+	
+	// we can now deduce the remaining width
+	int remaining_width = total_width - abs_widths_sum;
+	
+	// we do a second iteration to build the final widths list
+	for (int i = 0 ; i < columns_width_.count() ; ++ i) {
+		InsetColDimension icd = columns_width_.at(i);
+		if (icd.type == QET::RelativeToRemainingLength) {
+			final_widths[i] = int(remaining_width * icd.value / 100);
+		}
+	}
+	return(final_widths.toList());
+}
+
+int InsetTemplate::height() const {
+	int height = 0;
+	foreach(int row_height, rows_heights_) {
+		height += row_height;
+	}
+	return(height);
+}
+
+/**
+	Render the inset.
+	@param painter Painter to use to render the inset
+	@param diagram_context Diagram context to use to generate the inset strings
+	@param inset_width Width of the inset to render
+*/
+void InsetTemplate::render(QPainter &painter, const DiagramContext &diagram_context, int inset_width) const {
+	QList<int> widths = columnsWidth(inset_width);
+	int inset_height = height();
+	
+	// prepare the QPainter
+	painter.setPen(Qt::black);
+	painter.setBrush(Qt::white);
+	painter.setFont(QETApp::diagramTextsFont());
+	
+	// draw the inset border
+	painter.drawRect(QRect(0, 0, inset_width, inset_height));
+	
+	// run through each inidividual cell
+	for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
+		for (int i = 0 ; i < columns_width_.count() ; ++ i) {
+			if (cells_[i][j].spanner_cell) continue;
+			
+			// calculate the border rect of the current cell
+			int x = lengthRange(0, cells_[i][j].num_col, widths); 
+			int y = lengthRange(0, cells_[i][j].num_row, rows_heights_);
+			int w = lengthRange(cells_[i][j].num_col, cells_[i][j].num_col + 1 + cells_[i][j].col_span, widths);
+			int h = lengthRange(cells_[i][j].num_row, cells_[i][j].num_row + 1 + cells_[i][j].row_span, rows_heights_);
+			QRect cell_rect(x, y, w, h);
+			
+			// draw the border rect of the current cell
+			painter.drawRect(cell_rect);
+			
+			// render the inner content of the current cell
+			if (!cells_[i][j].logo_reference.isEmpty()) {
+				// the current cell appear to be a logo - we first look for the
+				// logo reference in our vector logos list, since they offer a
+				// potentially better (or, at least, not resolution-limited) rendering
+				if (vector_logos_.contains(cells_[i][j].logo_reference)) {
+					vector_logos_[cells_[i][j].logo_reference] -> render(&painter, cell_rect);
+				} else if (bitmap_logos_.contains(cells_[i][j].logo_reference)) {
+					painter.drawPixmap(cell_rect, *(bitmap_logos_[cells_[i][j].logo_reference]));
+				}
+			} else {
+				painter.drawText(cell_rect, cells_[i][j].alignment, finalTextForCell(cells_[i][j], diagram_context));
+			}
+			
+			// draw again the border rect of the current cell, without the brush this time
+			painter.setBrush(Qt::NoBrush);
+			painter.drawRect(cell_rect);
+		}
+	}
+}
+
+/**
+	@param cell A cell from this template
+	@param diagram_context Diagram context to use to generate the final text for the given cell
+	@return the final text that has to be drawn in the given cell
+*/
+QString InsetTemplate::finalTextForCell(const InsetCell &cell, const DiagramContext &diagram_context) const {
+	QString cell_text = cell.value;
+	
+	foreach (QString key, diagram_context.keys()) {
+		cell_text.replace("%{" + key + "}", diagram_context[key].toString());
+		cell_text.replace("%" + key,        diagram_context[key].toString());
+	}
+	if (cell.display_label && !cell.label.isEmpty()) {
+		cell_text = QString(tr(" %1 : %2", "inset content - please let the blank space at the beginning")).arg(cell.label).arg(cell_text);
+	} else {
+		cell_text = QString(tr(" %1")).arg(cell_text);
+	}
+	return(cell_text);
+}
+
+/**
+	@return the width between two borders
+	@param start start border number
+	@param end end border number
+*/
+int InsetTemplate::lengthRange(int start, int end, const QList<int> &lengths_list) const {
+	if (start > end || start >= lengths_list.count() || end > lengths_list.count()) {
+		qDebug() << Q_FUNC_INFO << "wont use" << start << "and" << end;
+		return(0);
+	}
+	
+	int length = 0;
+	for (int i = start ; i < end ; ++i) {
+		length += lengths_list[i];
+	}
+	return(length);
+}
+
+
+
+/**
+	Constructor
+*/
+InsetCell::InsetCell() {
+	num_row = num_col = -1;
+	row_span = col_span = 0;
+	display_label = is_null = true;
+	spanner_cell = 0;
+}
+
+/**
+	@return A string representing the inset cell
+*/
+QString InsetCell::toString() const {
+	if (is_null) return("InsetCell{null}");
+	QString span_desc = (row_span > 0 || col_span > 0) ? QString("+%3,%4").arg(row_span).arg(col_span) : QET::pointerString(spanner_cell);
+	QString base_desc = QString("InsetCell{ [%1, %2] %3 }").arg(num_row).arg(num_col).arg(span_desc);
+	return(base_desc);
+}

Added: branches/0.3/sources/insettemplate.h
===================================================================
--- branches/0.3/sources/insettemplate.h	                        (rev 0)
+++ branches/0.3/sources/insettemplate.h	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,92 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef INSET_TEMPLATE_H
+#define INSET_TEMPLATE_H
+#include <QtXml>
+#include <QtSvg>
+#include "diagramcontext.h"
+#include "insetcell.h"
+#include "qet.h"
+
+/**
+	This struct is a simple container associating a length with its type.
+	@see InsetColumnLength 
+*/
+struct InsetColDimension {
+	InsetColDimension(int v, QET::InsetColumnLength t = QET::Absolute) {
+		value = v;
+		type = t;
+	}
+	QET::InsetColumnLength type;
+	int value;
+};
+
+/**
+	This class represents an inset templ)ate for an electric diagram.
+	It can read from an XML document the layout of the table that graphically
+	represents the inset, and can produce a graphical rendering of it from a
+	diagram context (object embedding the informations of the diagram we want to
+	represent the inset.
+*/
+class InsetTemplate : public QObject {
+	Q_OBJECT
+	
+	// constructeurs, destructeur
+	public:
+	InsetTemplate(QObject * = 0);
+	virtual ~InsetTemplate();
+	private:
+	InsetTemplate(const InsetTemplate &);
+	
+	// methodes
+	public:
+	bool loadFromXmlFile(const QString &);
+	bool loadFromXmlElement(const QDomElement &);
+	void setContext(const DiagramContext &);
+	
+	QList<int> columnsWidth(int) const;
+	int height() const;
+	
+	void render(QPainter &, const DiagramContext &, int) const;
+	QString toString() const;
+	
+	protected:
+	bool loadLogos(const QDomElement &, bool = false);
+	bool loadLogo(const QDomElement &);
+	bool loadGrid(const QDomElement &);
+	bool loadCells(const QDomElement &);
+	
+	private:
+	void parseRows(const QString &);
+	void parseColumns(const QString &);
+	bool checkCell(const QDomElement &, InsetCell ** = 0);
+	void flushCells();
+	void initCells();
+	int lengthRange(int, int, const QList<int> &) const;
+	QString finalTextForCell(const InsetCell &, const DiagramContext &) const;
+	
+	// attributs
+	private:
+	QDomDocument xml_description_;
+	QHash<QString, QSvgRenderer *> vector_logos_;
+	QHash<QString, QPixmap *>      bitmap_logos_;
+	QList<int> rows_heights_;
+	QList<InsetColDimension> columns_width_;
+	QVector< QVector<InsetCell> > cells_;
+};
+#endif

Added: branches/0.3/sources/insettemplaterenderer.cpp
===================================================================
--- branches/0.3/sources/insettemplaterenderer.cpp	                        (rev 0)
+++ branches/0.3/sources/insettemplaterenderer.cpp	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,96 @@
+#include "insettemplaterenderer.h"
+#include "insettemplate.h"
+
+/**
+	Constructor
+	@param parnet Parent QObject of this renderer
+*/
+InsetTemplateRenderer::InsetTemplateRenderer(QObject *parent) :
+	QObject(parent),
+	inset_template_(0),
+	last_known_inset_width_(-1)
+{
+}
+
+/**
+	Destructor
+*/
+InsetTemplateRenderer::~InsetTemplateRenderer() {
+}
+
+/**
+	@return the inset template used for the rendering
+*/
+const InsetTemplate *InsetTemplateRenderer::insetTemplate() const {
+	return(inset_template_);
+}
+
+/**
+	@param inset_template Inset template to render.
+*/
+void InsetTemplateRenderer::setInsetTemplate(const InsetTemplate *inset_template) {
+	if (inset_template != inset_template_) {
+		inset_template_ = inset_template;
+		invalidateRenderedTemplate();
+	}
+}
+
+/**
+	@param context Diagram Context to use when rendering the inset
+*/
+void InsetTemplateRenderer::setContext(const DiagramContext &context) {
+	context_ = context;
+	invalidateRenderedTemplate();
+}
+
+/**
+	@return the height of the rendered template, or -1 if no template has been
+	set for this renderer.
+	@see InsetTemplate::height()
+*/
+int InsetTemplateRenderer::height() const {
+	if (!inset_template_) return(-1);
+	return(inset_template_ -> height());
+}
+
+/**
+	Render the inset.
+	@param provided_painter QPainter to use to render the inset.
+	@param inset_width The total width of the inset to render
+*/
+void InsetTemplateRenderer::render(QPainter *provided_painter, int inset_width) {
+	if (!inset_template_) return;
+	
+	// Do we really need to calculate all this again?
+	if (inset_width != last_known_inset_width_ || rendered_template_.isNull()) {
+		renderToQPicture(inset_width);
+	}
+	
+	provided_painter -> save();
+	rendered_template_.play(provided_painter);
+	provided_painter -> restore();
+}
+
+/**
+	Renders the inset to the internal QPicture
+	@param inset_width Width of the inset to render
+*/
+void InsetTemplateRenderer::renderToQPicture(int inset_width) {
+	if (!inset_template_) return;
+	
+	// we render the template on our internal QPicture
+	QPainter painter(&rendered_template_);
+	
+	inset_template_ -> render(painter, context_, inset_width);
+	
+	// memorize the last known width
+	last_known_inset_width_ = inset_width;
+}
+
+/**
+	Invalidates the previous rendering of the template by resetting the internal
+	QPicture.
+*/
+void InsetTemplateRenderer::invalidateRenderedTemplate() {
+	rendered_template_ = QPicture();
+}

Added: branches/0.3/sources/insettemplaterenderer.h
===================================================================
--- branches/0.3/sources/insettemplaterenderer.h	                        (rev 0)
+++ branches/0.3/sources/insettemplaterenderer.h	2010-12-19 18:08:08 UTC (rev 1129)
@@ -0,0 +1,45 @@
+/*
+	Copyright 2006-2010 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 2 of the License, or
+	(at your option) any later version.
+	
+	QElectroTech is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef INSET_TEMPLATE_RENDERER_H
+#define INSET_TEMPLATE_RENDERER_H
+#include <QPicture>
+#include "diagramcontext.h"
+class InsetTemplate;
+class InsetTemplateRenderer : public QObject {
+	Q_OBJECT
+	
+	public:
+	InsetTemplateRenderer(QObject * = 0);
+	virtual ~InsetTemplateRenderer();
+	const InsetTemplate *insetTemplate() const;
+	void setInsetTemplate(const InsetTemplate *);
+	void setContext(const DiagramContext &context);
+	int height() const;
+	void render(QPainter *, int);
+	
+	private:
+	void renderToQPicture(int);
+	void invalidateRenderedTemplate();
+	
+	private:
+	const InsetTemplate *inset_template_;
+	QPicture rendered_template_;
+	DiagramContext context_;
+	int last_known_inset_width_;
+};
+#endif

Modified: branches/0.3/sources/qet.cpp
===================================================================
--- branches/0.3/sources/qet.cpp	2010-12-19 17:16:30 UTC (rev 1128)
+++ branches/0.3/sources/qet.cpp	2010-12-19 18:08:08 UTC (rev 1129)
@@ -515,3 +515,16 @@
 	
 	return(first_canonical_path == second_canonical_path);
 }
+
+/**
+	@param icl an InsetColumnLength object
+	@see InsetColumnLength
+	@return a string describing the type of this InsetColumnLength object
+*/
+QString QET::insetColumnLengthToString(const InsetColumnLength  &icl) {
+	QString type_str;
+	if (icl== Absolute) type_str = "absolute";
+	else if (icl == RelativeToTotalLength) type_str = "relative to total";
+	else if (icl == RelativeToRemainingLength) type_str = "relative to remaining";
+	return(type_str);
+}

Modified: branches/0.3/sources/qet.h
===================================================================
--- branches/0.3/sources/qet.h	2010-12-19 17:16:30 UTC (rev 1128)
+++ branches/0.3/sources/qet.h	2010-12-19 18:08:08 UTC (rev 1129)
@@ -97,6 +97,13 @@
 		ElementsArea     ///< Exporte le contenu du schema sans le cadre et le cartouche
 	};
 	
+	/// enum used to specify the type of a length
+	enum InsetColumnLength {
+		Absolute,                   ///< the length is absolute and should be applied as is
+		RelativeToTotalLength,      ///< the length is just a fraction of the total available length
+		RelativeToRemainingLength   ///< the length is just a fraction of the length that is still available when other types of lengths have been removed
+	};
+	
 	QET::Orientation nextOrientation(QET::Orientation);
 	QET::Orientation previousOrientation(QET::Orientation);
 	QET::Orientation orientationFromString(const QString &);
@@ -125,5 +132,6 @@
 	QString pointerString(void *);
 	qreal correctAngle(const qreal &);
 	bool compareCanonicalFilePaths(const QString &, const QString &);
+	QString insetColumnLengthToString(const InsetColumnLength  &);
 }
 #endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/