From: Stéphane Domas Date: Wed, 26 Apr 2017 12:17:46 +0000 (+0200) Subject: 1st commit of all files X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/blast.git/commitdiff_plain/abbc64cf04a35ab3549d5c516f44c7c5921baa63?ds=sidebyside;hp=-c 1st commit of all files --- abbc64cf04a35ab3549d5c516f44c7c5921baa63 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f44bef8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/archive/* +/build/* +/Makefile +/configure +*~ +*.aux +*.log +*.dvi +*.bbl +*.blg \ No newline at end of file diff --git a/AbstractBlock.cpp b/AbstractBlock.cpp new file mode 100644 index 0000000..6e9cc86 --- /dev/null +++ b/AbstractBlock.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include "AbstractInterface.h" +#include "BlockParameter.h" + +AbstractBlock::AbstractBlock() { + name = ""; + parent = NULL; +} + +AbstractBlock::AbstractBlock(const QString& _name) { + name = _name; + parent = NULL; +} + +AbstractBlock::~AbstractBlock() { + + foreach(AbstractInterface* iface, inputs) { + delete iface; + } + foreach(AbstractInterface* iface, outputs) { + delete iface; + } + foreach(AbstractInterface* iface, bidirs) { + delete iface; + } + inputs.clear(); + outputs.clear(); + bidirs.clear(); + foreach(BlockParameter* p, params) { + delete p; + } + params.clear(); +} + +void AbstractBlock::setName(const QString& str) { + name = str; +} + +void AbstractBlock::setParent(AbstractBlock* _parent) { + parent = _parent; +} + +bool AbstractBlock::isReferenceBlock() { + return false; +} + +bool AbstractBlock::isFunctionalBlock() { + return false; +} + +bool AbstractBlock::isGroupBlock() { + return false; +} + +void AbstractBlock::addParameter(BlockParameter *param) { + params.append(param); +} + + +BlockParameter* AbstractBlock::getParameterFromName(QString name) { + foreach(BlockParameter* p, params) { + if (p->getName() == name) return p; + } + return NULL; +} + +void AbstractBlock::addInterface(AbstractInterface *inter) { + if(inter->getDirection() == AbstractInterface::Input){ + inputs.append(inter); + } else if(inter->getDirection() == AbstractInterface::Output){ + outputs.append(inter); + } else if(inter->getDirection() == AbstractInterface::InOut){ + bidirs.append(inter); + } +} + +void AbstractBlock::removeInterface(AbstractInterface *inter) { + /* CAUTION: no check is done about the connection state of this interface + Thus, if it is still connected to/from, there will be a crash + */ + if(inter->getDirection() == AbstractInterface::Input){ + inputs.removeAll(inter); + } else if(inter->getDirection() == AbstractInterface::Output){ + outputs.removeAll(inter); + } else if(inter->getDirection() == AbstractInterface::InOut){ + bidirs.removeAll(inter); + } + delete inter; +} + +void AbstractBlock::defineBlockParam(BlockParameter *param) +{ + cout << "definition of param : " << param->getName().toStdString() << endl; + bool ok = false; + QString value = QInputDialog::getText(NULL, "Block parameter", "value for the "+ param->getName() +" parameter of " + param->getOwner()->getName() + "?", QLineEdit::Normal, param->getValue().toString(), &ok); + + while (!ok && value.isEmpty()) + { + QMessageBox::critical(NULL, "Error", "You have to insert a value for the parameter or accept the default value !"); + value = QInputDialog::getText(NULL, "Block parameter", "value for the "+ param->getName() +" parameter of " + param->getOwner()->getName() + " ?", QLineEdit::Normal, param->getValue().toString(), &ok); + } + param->setValue(value); +} + +QList AbstractBlock::getInterfaces() { + QList list; + list.append(inputs); + list.append(outputs); + list.append(bidirs); + return list; +} + +AbstractInterface* AbstractBlock::getIfaceFromName(QString name) { + + foreach(AbstractInterface* iface, inputs) { + if (iface->getName() == name) return iface; + } + foreach(AbstractInterface* iface, outputs) { + if (iface->getName() == name) return iface; + } + foreach(AbstractInterface* iface, bidirs) { + if (iface->getName() == name) return iface; + } + return NULL; +} + +bool AbstractBlock::isWBConfigurable() { + + foreach(BlockParameter* p, params) { + if (p->isWishboneParameter()) return true; + } + return false; +} + +QList AbstractBlock::getUserParameters() { + QList lst; + foreach(BlockParameter* p, params) { + if (p->isUserParameter()) lst.append(p); + } + return lst; +} + +QList AbstractBlock::getGenericParameters() { + QList lst; + foreach(BlockParameter* p, params) { + if (p->isGenericParameter()) lst.append(p); + } + return lst; +} + +QList AbstractBlock::getPortParameters() { + QList lst; + foreach(BlockParameter* p, params) { + if (p->isPortParameter()) lst.append(p); + } + return lst; +} + +QList AbstractBlock::getWishboneParameters() { + QList lst; + foreach(BlockParameter* p, params) { + if (p->isWishboneParameter()) lst.append(p); + } + return lst; +} diff --git a/AbstractBlock.h b/AbstractBlock.h new file mode 100644 index 0000000..2c89cbf --- /dev/null +++ b/AbstractBlock.h @@ -0,0 +1,78 @@ +#ifndef __ABSTRACTBLOCK_H__ +#define __ABSTRACTBLOCK_H__ + +#include + +#include + +class AbstractInterface; +class BlockParameter; + +#define AB_TO_REF(ptr) ((ReferenceBlock*)ptr) +#define AB_TO_FUN(ptr) ((FunctionalBlock*)ptr) +#define AB_TO_GRP(ptr) ((GroupBlock*)ptr) + +using namespace std; +using namespace Qt; + +class AbstractBlock { + +public: + + AbstractBlock(); + AbstractBlock(const QString& _name); + virtual ~AbstractBlock(); + + // getters + inline QString getName() { return name; } + inline QList getParameters() { return params; } + inline QList getInputs() { return inputs; } + inline QList getOutputs() { return outputs; } + inline QList getBidirs() { return bidirs; } + QList getUserParameters(); + QList getGenericParameters(); + QList getPortParameters(); + QList getWishboneParameters(); + inline AbstractBlock* getParent() { return parent; } + // setters + void setName(const QString& str); + virtual void setParent(AbstractBlock* _parent); + + // testers + virtual bool isReferenceBlock(); + virtual bool isFunctionalBlock(); + virtual bool isGroupBlock(); + bool isWBConfigurable(); + + // others + virtual void parametersValidation(QList* checkedBlocks, QList* blocksToConfigure) = 0; // ugly but usefull + + void addParameter(BlockParameter *param); + void addInterface(AbstractInterface *inter); + void removeInterface(AbstractInterface *inter); + void defineBlockParam(BlockParameter *param); + + QList getInterfaces(); + AbstractInterface* getIfaceFromName(QString name); + BlockParameter* getParameterFromName(QString name); + +protected: + + + QString name; + + // parameters + QList params; + + // interfaces + QList inputs; + QList outputs; + QList bidirs; + + // others + + // NB: only GroupBlock and FunctionalBlock have a real parent + AbstractBlock* parent; +}; + +#endif // __ABSTRACTBLOCK_H__ diff --git a/AbstractBoxItem.cpp b/AbstractBoxItem.cpp new file mode 100644 index 0000000..0afbe29 --- /dev/null +++ b/AbstractBoxItem.cpp @@ -0,0 +1,255 @@ +#include "AbstractBoxItem.h" + +#include "Parameters.h" + +#include "Dispatcher.h" +#include "InterfaceItem.h" +#include "ConnectionItem.h" + +#include "AbstractBlock.h" +#include "GroupScene.h" +#include "AbstractInterface.h" +#include "ConnectedInterface.h" + + +AbstractBoxItem:: AbstractBoxItem(AbstractBlock *_refBlock, Dispatcher *_dispatcher, Parameters *_params, QGraphicsItem *parent) : QGraphicsItem(parent) { + dispatcher = _dispatcher; + params = _params; + refBlock = _refBlock; + QFont fontId("Arial",10); + QFontMetrics fmId(fontId); + nameWidth = fmId.width(refBlock->getName()); + nameHeight = fmId.height(); + nameMargin = 10; + ifaceMargin = 10; + + // the six following values will be override in subclass constructors + minimumBoxWidth = 0; + minimumBoxHeight = 0; + boxWidth = 0; + boxHeight = 0; + totalWidth = 0; + totalHeight = 0; + + originPoint = QPointF(0.0,0.0); + + selected = false; + currentInterface = NULL; + rstClkVisible = false; + + setAcceptHoverEvents(true); + + // NOTE : initInterfaces() is only called in subclasses +} + +AbstractBoxItem::~AbstractBoxItem() { + foreach(InterfaceItem* inter, interfaces) { + delete inter; + } + interfaces.clear(); +} + +bool AbstractBoxItem::isBoxItem() { + return false; +} + +bool AbstractBoxItem::isGroupItem() { + return false; +} + +void AbstractBoxItem::initInterfaces() +{ + /* TO DO : creating all needed InterfaceItem, with by default, input at west and output at east */ + int orientation = Parameters::West; + + foreach(AbstractInterface *inter, refBlock->getInterfaces()){ + if(inter->getPurpose() != AbstractInterface::Wishbone){ + InterfaceItem *item; + if(inter->getDirection() == AbstractInterface::Input){ + orientation = Parameters::West; + } else if(inter->getDirection() == AbstractInterface::Output){ + orientation = Parameters::East; + } else if(inter->getDirection() == AbstractInterface::InOut){ + orientation = Parameters::North; + } + item = new InterfaceItem(0.0 , orientation, (ConnectedInterface *)inter, this, params); + interfaces.append(item); + } + } +} + +InterfaceItem* AbstractBoxItem::searchInterfaceByName(QString name) { + foreach(InterfaceItem *inter, interfaces){ + if(inter->getName() == name) + return inter; + } + return NULL; +} + +InterfaceItem* AbstractBoxItem::searchInterfaceByRef(ConnectedInterface *ref) { + foreach(InterfaceItem *inter, interfaces){ + if(inter->refInter == ref) { + return inter; + } + } + return NULL; +} + +void AbstractBoxItem::addInterface(InterfaceItem *i, bool resetPosition) { + interfaces.append(i); + if (resetPosition) resetInterfacesPosition(); + updateGeometry(); + update(); +} + +void AbstractBoxItem::removeInterface(InterfaceItem *i) { + // NB : removing from model is done in dispatcher + interfaces.removeOne(i); + delete i; + + //resetInterfacesPosition(); + updateGeometry(); + update(); +} + + +void AbstractBoxItem::resetInterfacesPosition() { + + int nbNorth=0, nbSouth=0, nbEast=0, nbWest=0; + double cntNorth=1.0,cntSouth=1.0,cntEast=1.0,cntWest=1.0; + double positionRatio = 1.0; + + + foreach(InterfaceItem* inter, interfaces) { + // only data interfaces and if needed time and reset + if(inter->refInter->getPurpose() == AbstractInterface::Data || inter->getOwner()->isRstClkVisible()){ + if(inter->getOrientation() == Parameters::North){ + nbNorth++; + } else if(inter->getOrientation() == Parameters::South){ + nbSouth++; + } else if(inter->getOrientation() == Parameters::East){ + nbEast++; + } else if(inter->getOrientation() == Parameters::West){ + nbWest++; + } + } + } + + foreach(InterfaceItem* inter, interfaces) { + + if(inter->refInter->getPurpose() == AbstractInterface::Data || inter->getOwner()->isRstClkVisible()){ + + if(inter->getOrientation() == Parameters::North){ + positionRatio = cntNorth/(double)(nbNorth+1); + cntNorth += 1.0; + } else if(inter->getOrientation() == Parameters::South){ + positionRatio = cntSouth/(double)(nbSouth+1); + cntSouth += 1.0; + } else if(inter->getOrientation() == Parameters::East){ + positionRatio = cntEast/(double)(nbEast+1); + cntEast += 1.0; + } else if(inter->getOrientation() == Parameters::West){ + positionRatio = cntWest/(double)(nbWest+1); + cntWest += 1.0; + } + inter->setPositionRatio(positionRatio); + inter->updatePosition(); + } + } +} + +void AbstractBoxItem::deplaceInterface(QPointF pos) { + double positionRatio; + if(currentInterface->getOrientation() == Parameters::North || currentInterface->getOrientation() == Parameters::South){ + if(pos.x() < 0){ + positionRatio = 0; + if(pos.y() > 0 && pos.y() < boxHeight){ + currentInterface->setOrientation(Parameters::West); + } + } else if(pos.x() > boxWidth){ + positionRatio = 1; + if(pos.y() > 0 && pos.y() < boxHeight){ + currentInterface->setOrientation(Parameters::East); + } + } else { + positionRatio = ((double) pos.x())/boxWidth; + } + } else { + + if(pos.y() < 0){ + positionRatio = 0; + if(pos.x() > 0 && pos.x() < boxWidth){ + currentInterface->setOrientation(Parameters::North); + } + } else if(pos.y() > boxHeight){ + positionRatio = 1; + if(pos.x() > 0 && pos.x() < boxWidth){ + currentInterface->setOrientation(Parameters::South); + } + } else { + positionRatio = ((double) pos.y())/boxHeight; + } + } + currentInterface->setPositionRatio(positionRatio); + currentInterface->updatePosition(); +} + +QRectF AbstractBoxItem::boundingRect() const { + // returns a QRectF that contains the block (i.e the main rectangle, interfaces, title, ...) + QPointF p = originPoint - QPointF(nameHeight,nameHeight); + QSizeF s(totalWidth+2*nameHeight,totalHeight+2*nameHeight); + return QRectF(p,s); +} + + +/* isInterface() : return true if there are some interfaces + with the given orientation (N,S,E,O) +*/ +bool AbstractBoxItem::isInterfaces(int orientation) const { + foreach(InterfaceItem* inter, interfaces) { + if (inter->getOrientation() == orientation) return true; + } + return false; +} + +int AbstractBoxItem::nbInterfacesByOrientation(int orientation) { + int nb = 0; + foreach(InterfaceItem* inter, interfaces) { + if ((inter->visible) && (inter->getOrientation() == orientation)) nb++; + } + return nb; +} + +void AbstractBoxItem::updateInterfacesAndConnections() { + + // update all interfaces positions + foreach(InterfaceItem *item, interfaces){ + item->updatePosition(); + } + if (getScene() != NULL) { + // update all connections from/to this block + foreach(ConnectionItem *item, getScene()->getConnectionItems()){ + if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) { + item->setPathes(); + } + } + } +} + +void AbstractBoxItem::setDimension(int x, int y) { + boxWidth = x; + boxHeight = y; +} + +InterfaceItem* AbstractBoxItem::getInterfaceFromCursor(qreal x, qreal y) { + + foreach(InterfaceItem* inter, interfaces) { + if(x > inter->boundingRect().x() && x < (inter->boundingRect().x() + inter->boundingRect().width())){ + if(y > inter->boundingRect().y() && y < (inter->boundingRect().y() + inter->boundingRect().height())){ + return inter; + } + } + } + /* TO DO : check each interfaces if it contains x,y. If yes, return that interface */ + return NULL; +} diff --git a/AbstractBoxItem.h b/AbstractBoxItem.h new file mode 100644 index 0000000..6eeb46c --- /dev/null +++ b/AbstractBoxItem.h @@ -0,0 +1,112 @@ +#ifndef __ABSTRACTBOXITEM_H__ +#define __ABSTRACTBOXITEM_H__ + +#include + +#include +#include +#include + +class Dispatcher; +class InterfaceItem; +class Parameters; +class AbstractBlock; +class GroupScene; +class ConnectedInterface; + +class AbstractBoxItem : public QGraphicsItem { + +public: + + enum BorderType { NoBorder = 0, BorderEast, BorderNorth, BorderWest, BorderSouth, CornerSouthEast, Title}; + enum ChangeType { Resize = 0, InterfaceMove }; + + AbstractBoxItem(AbstractBlock *_refBlock, Dispatcher *_dispatcher, Parameters *_params, QGraphicsItem* parent = Q_NULLPTR); + + virtual ~AbstractBoxItem(); + + // getters + inline AbstractBlock* getRefBlock() { return refBlock; } + inline int getWidth() { return boxWidth;} + inline int getHeight() { return boxHeight;} + inline int getTotalWidth() { return totalWidth;} + inline int getTotalHeight() { return totalHeight; } + inline QList getInterfaces() { return interfaces; } + inline InterfaceItem *getCurrentInterface() { return currentInterface; } + inline int getId(){ return id; } + inline GroupScene* getScene() { return (GroupScene*)(scene()); } + inline int getIfaceMargin() { return ifaceMargin; } + inline int getNameMargin() { return nameMargin; } + inline QPointF getOriginPoint() { return originPoint; } + + // setters + inline void setId(int id){ this->id = id; } + inline void setSelected(bool _selected) { selected = _selected; } + inline void setRstClkVisible(bool b){ rstClkVisible = b;} + void setDimension(int x, int y); + inline void setCurrentInterface(InterfaceItem* iface) { currentInterface = iface; } + + // testers + virtual bool isBoxItem(); + virtual bool isGroupItem(); + inline bool isSelected() { return selected; } + inline bool isRstClkVisible(){ return rstClkVisible;} + bool isInterfaces(int orientation) const; + + // others + + void addInterface(InterfaceItem* i, bool resetPosition = false); + void removeInterface(InterfaceItem* i); + void resetInterfacesPosition(); + void deplaceInterface(QPointF pos); + void updateInterfacesAndConnections(); + + InterfaceItem *searchInterfaceByName(QString name); + InterfaceItem *searchInterfaceByRef(ConnectedInterface* ref); + InterfaceItem* getInterfaceFromCursor(qreal x, qreal y); + +protected: + Dispatcher *dispatcher; + Parameters *params; + QList interfaces; + /* NOTE : the reference block may be a FunctionalBlock or a GroupBlock, depending on the fact + that the real instace will be of FunctionalBlock or GroupBlock + */ + AbstractBlock *refBlock; + + InterfaceItem* currentInterface; // currently clicked interface in ItemEdition mode + + BorderType currentBorder; // which border cursor is on + QPointF cursorPosition; + + int id; + int boxWidth; // the width of the main box (without interface, title, ...) + int boxHeight; // the height of the main box (without interface, title, ...) + int minimumBoxWidth; // minimum width of the main box: may be recomputed if position/number of interface changes + int minimumBoxHeight; // minimum height of the main box: may be recomputed if position/number of interface changes + int totalWidth; // width and heigth taking into account interfaces,title, ... + int totalHeight; + int nameWidth; // the width of the box (group or block) name in Arial 10 + int nameHeight; // the height of the name in Arial 10 + int nameMargin; // the margin around each side of the name + int ifaceMargin; // the margin around each side of interfaces' name + QPointF originPoint; // the left-top point that is the origin of the bounding box + + bool selected; + bool rstClkVisible; + + QPointF currentPosition; // the start point for resize + + virtual void updateMinimumSize() = 0; // modify the minimum size + virtual bool updateGeometry(ChangeType type) = 0; // modify the originPoint and the total dimension + + QRectF boundingRect() const; + /* pure virtual method inherited from QGraphicsItem : + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) =0; + virtual QRectF boundingRect() const =0; + */ + void initInterfaces(); + int nbInterfacesByOrientation(int orientation); +}; + +#endif // __ABSTRACTBOXITEM_H__ diff --git a/AbstractInterface.cpp b/AbstractInterface.cpp new file mode 100644 index 0000000..25cd2d3 --- /dev/null +++ b/AbstractInterface.cpp @@ -0,0 +1,279 @@ +#include "AbstractInterface.h" +#include "BlockParameterPort.h" +#include "AbstractBlock.h" + +AbstractInterface::AbstractInterface(AbstractBlock* _owner) { + + owner = _owner; + name = ""; + width = "1"; + direction = Input; + purpose = Data; + level = Basic; + type = Boolean; + +} + +AbstractInterface::AbstractInterface(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _width, int _direction, int _purpose, int _level) { + + owner = _owner; + name = _name; + width = _width; + direction = _direction; + purpose = _purpose; + level = _level; + if (direction == InOut) { + level = Top; + } + type = typeFromString(_type); +} + +AbstractInterface::AbstractInterface(AbstractInterface* other) { + owner = NULL; + name = other->name; + type = other->type; + width = other->width; + direction = other->direction; + purpose = other->purpose; + level = other->level; +} + +AbstractInterface::~AbstractInterface() { + +} + +bool AbstractInterface::isReferenceInterface() { + return false; +} + +bool AbstractInterface::isFunctionalInterface() { + return false; +} + +bool AbstractInterface::isGroupInterface() { + return false; +} + +QString AbstractInterface::getPurposeString() { + QString str; + switch(purpose){ + case AbstractInterface::Data: + str = QString("data"); + break; + case AbstractInterface::Clock: + str = QString("clock"); + break; + case AbstractInterface::Reset: + str = QString("reset"); + break; + case AbstractInterface::Wishbone: + str = QString("wishbone"); + break; + } + return str; +} + +QString AbstractInterface::getDirectionString() { + QString str; + switch(direction){ + case AbstractInterface::Input: + str = QString("input"); + break; + case AbstractInterface::Output: + str = QString("output"); + break; + case AbstractInterface::InOut: + str = QString("inout"); + break; + } + return str; +} + +QString AbstractInterface::getLevelString() { + QString str; + switch(level){ + case AbstractInterface::Basic: + str = QString("basic"); + break; + case AbstractInterface::Top: + str = QString("top"); + break; + } + return str; +} + +double AbstractInterface::getDoubleWidth() throw(QException) { + + static QString fctName = "AbstractInterface::getDoubleWidth()"; + #ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; + #endif + + /* + cout << "start AbstractInterface::getDoubleWidth()" << endl; + bool ok; + double width = getWidth().toDouble(&ok); + + if(!ok){ + ArithmeticEvaluator *evaluator = new ArithmeticEvaluator; + cout << "evaluator created!" << endl; + evaluator->setExpression(getWidth()); + cout << "expression defined!" << endl; + foreach(BlockParameter *param, getOwner()->getParameters()){ + evaluator->setVariableValue(param->getName(), param->getIntValue()); + cout << "param : " << param->getName().toStdString() << " evaluated!" << endl; + } + width = evaluator->evaluate(); + cout << "expression evaluated succefully!" << endl; + } + cout << "real width : " << width << endl; + return width; + */ + + return 1.0; +} + +void AbstractInterface::setPurpose(int _purpose) { + if ((_purpose>=Data) && (_purpose <= Wishbone)) { + purpose = _purpose; + } +} + +void AbstractInterface::setDirection(int _direction) { + if ((_direction > Input) && (_direction <= InOut)) { + direction = _direction; + } + if (direction == InOut) { + level = Top; + } +} + +void AbstractInterface::setLevel(int _level) { + if ((_level >= Basic) << (_level < Top)) { + level = _level; + } + if (direction == InOut) { + level = Top; + } +} + + + +int AbstractInterface::getIntDirection(QString str) +{ + if(str == "input") return Input; + if(str == "output") return Output; + if(str == "inOut") return InOut; + return -1; +} + +int AbstractInterface::getIntLevel(QString str) +{ + if(str == "basic") return Basic; + if(str == "top") return Top; + return -1; +} + +QString AbstractInterface::getTypeString() { + + if (type == Boolean) { + return "boolean"; + } + else if (type == Natural) { + return "natural"; + } + else if (type == Expression) { + return "expression"; + } + return "invalid_type"; +} + +int AbstractInterface::typeFromString(const QString &_type) { + + int ret; + if (_type == "expression") { + ret = Expression; + } + else if (_type == "boolean") { + ret = Boolean; + } + else if (_type == "natural") { + ret = Natural; + } + return ret; +} + +QString AbstractInterface::toVHDL(int context, int flags) throw(Exception) { + + if (isReferenceInterface()) throw(Exception(IFACE_INVALID_TYPE)); + + QString msb = width; + QString ret=""; + bool ok; + if ((context == BlockParameter::Entity) || (context == BlockParameter::Component)) { + + QString formatBool = "%1 : %2 std_logic"; + QString formatVector = "%1 : %2 std_logic_vector(%3 downto %4)"; + if ((flags & BlockParameter::NoComma) == 0) { + formatBool.append(";"); + formatVector.append(";"); + } + QString orientation=""; + if (direction == Input) { + orientation = "in"; + } + else if (direction == Output) { + orientation = "out"; + } + else { + orientation = "inout"; + } + if (type == Boolean) { + ret = formatVector.arg(name).arg(orientation); + } + else if (type == Natural) { + int w = width.toInt(&ok); + if (!ok) { + throw(Exception(INVALID_VALUE)); + } + else { + w -= 1; + ret = formatVector.arg(name).arg(orientation).arg(w).arg("0"); + } + } + else if (type == Expression) { + /* must check the following conditions : + - if it contains user/port parameters : must evaluate their numeric value + - if it contains generic parameters : just remove the $ -> the expression is not arithmetically evaluated. + */ + QList listGenerics = owner->getGenericParameters(); + QList listUsers = owner->getUserParameters(); + QList listPorts = owner->getPortParameters(); + foreach(BlockParameter* p, listUsers) { + QString var = "$"; + var.append(p->getName()); + if (width.contains(var)) { + int w = p->getValue().toInt(&ok); + if (!ok) throw(Exception(INVALID_VALUE)); + msb.replace(var,p->getValue().toString()); + } + } + foreach(BlockParameter* p, listPorts) { + QString var = "$"; + var.append(p->getName()); + if (width.contains(var)) { + BlockParameterPort* pp = (BlockParameterPort*)p; + AbstractInterface* iface = owner->getIfaceFromName(pp->getIfaceName()); + + int w = p->getValue().toInt(&ok); + if (!ok) throw(Exception(INVALID_VALUE)); + msb.replace(var,p->getValue().toString()); + } + } + + ret = formatVector.arg(name).arg(orientation).arg("toto").arg("0"); + } + } + return ret; +} + diff --git a/AbstractInterface.h b/AbstractInterface.h new file mode 100644 index 0000000..78414c3 --- /dev/null +++ b/AbstractInterface.h @@ -0,0 +1,107 @@ +#ifndef __ABSTRACTINTERFACE_H__ +#define __ABSTRACTINTERFACE_H__ + +#include + +#include +#include + +class AbstractBlock; + +#include "Exception.h" +class Exception; + +#define AI_TO_REF(ptr) ((ReferenceInterface*)ptr) +#define AI_TO_FUN(ptr) ((FunctionalInterface*)ptr) +#define AI_TO_GRP(ptr) ((GroupInterface*)ptr) + +using namespace std; +using namespace Qt; + + +class AbstractInterface { + +public : + + enum IfaceWidthType { Expression = 1, Boolean, Natural}; + enum IfacePurpose { Data = 1, Clock = 2, Reset = 3, Wishbone = 4 }; + enum IfaceDirection { Input = 1, Output = 2, InOut = 3 }; + enum IfaceLevel { Basic = 1, Top = 2 }; + enum IfaceVHDLContext { Entity = 1, Component = 2, Architecture = 3 }; // NB : 3 is when creating an instance of the block that owns this iface + enum IfaceVHDLFlags { NoComma = 1 }; + + static int getIntDirection(QString str); + static int getIntLevel(QString str); + + AbstractInterface(AbstractBlock* _owner); + AbstractInterface(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _width, int _direction, int _purpose, int _level); + AbstractInterface(AbstractInterface* other); + virtual ~AbstractInterface(); + + // getters + inline QString getName() { return name;} + inline int getType() { return type; } + QString getTypeString(); + inline QString getWidth() { return width;} + inline int getPurpose() { return purpose;} + QString getPurposeString(); + inline int getDirection() { return direction;} + QString getDirectionString(); + inline int getLevel() { return level;} + QString getLevelString(); + inline AbstractBlock *getOwner() { return owner;} + + double getDoubleWidth() throw(QException); + + //virtual QList getConnectedTo() = 0; + + /* NB: only GroupInterface and FunctionalInterface have a connectedFrom, so + defining getConnectedFrom as pure virtual is normal, usefull even though it is ugly :-) + */ + virtual AbstractInterface* getConnectedFrom() = 0; + + // setters + inline void setOwner(AbstractBlock* _owner) { owner = _owner; } + inline void setName(const QString& _name) { name = _name; } + inline void setWidth(const QString& _width) { width = _width; } + inline void setType(int _type) { type = _type;} + inline void setType(const QString& _type) { type = typeFromString(_type);} + void setPurpose(int _purpose); + void setDirection(int _direction); + void setLevel(int _level); + + // testers + virtual bool isReferenceInterface(); + virtual bool isFunctionalInterface(); + virtual bool isGroupInterface(); + //virtual bool isConnectedTo() = 0; + //virtual bool isConnectedFrom() = 0; + //virtual bool canConnectTo(AbstractInterface* iface) = 0; // returns yes if this can be connected to iface, no if not + //virtual bool canConnectFrom(AbstractInterface* iface) = 0; // returns yes if this can be connected from iface, no if not + + // others + virtual AbstractInterface *clone() = 0; + + //virtual bool addConnectedTo(AbstractInterface *inter) = 0; + //virtual void removeConnectedTo(AbstractInterface *inter) = 0; + //virtual bool setConnectedFrom(AbstractInterface* inter) = 0; + //virtual void clearConnectedTo() = 0; + //virtual void clearConnections() = 0; + //virtual void connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception) = 0; + int typeFromString(const QString &_type); + + QString toVHDL(int context, int flags) throw(Exception); + +protected: + QString name; + int type; + QString width; + int purpose; + int direction; + int level; + + AbstractBlock* owner; +}; + + +#endif // __ABSTRACTINTERFACE_H__ diff --git a/ArithmeticEvaluator.cpp b/ArithmeticEvaluator.cpp new file mode 100644 index 0000000..60db08e --- /dev/null +++ b/ArithmeticEvaluator.cpp @@ -0,0 +1,438 @@ +/*-==============================================================- + +file : ArithmeticEvaluator.cpp + +creation date : 19/05/2015 + +author : S. Domas (sdomas@univ-fcomte.fr) + +description : + +supp. infos : saved in UTF-8 [éè] + +-==============================================================-*/ +#include "ArithmeticEvaluator.h" +#include + +ArithmeticEvaluator::ArithmeticEvaluator() { + opMarkers = "+-*/"; + varMarkers = "$"; + expression = QStringList(); + /* CAUTION : function are mandatory using ( ) to encapsulate the operand + since spaces are removed. Thus, an expression like sin 10 will lead to + sin10 after spaces removal, and thus becomes invalid. + */ + fctMarkers << "sin" << "cos" << "log10" << "log2" << "log" << "ceil" << "floor" << "round"; +} + +ArithmeticEvaluator::ArithmeticEvaluator(const QString& _expression) throw(int) { + opMarkers = "+-*/"; + varMarkers = "$"; + fctMarkers << "sin" << "cos" << "log10" << "log2" << "log" << "ceil" << "floor" << "round"; + try { + setExpression(_expression); + } + catch(int e) { + throw(e); + } +} + +void ArithmeticEvaluator::setExpression(const QString& _expression) throw(int) { + try { + convert(_expression); + } + catch(int e) { + throw(e); + } +} + +void ArithmeticEvaluator::print() { + foreach(QString elt, expression) { + cout << qPrintable(elt) << " "; + } + cout << endl; +} + +double ArithmeticEvaluator::evalFunction(int indexFunc, double value) { + double res = 0.0; + if (indexFunc == 0) { + res = sin(value); + } + else if (indexFunc == 1) { + res = cos(value); + } + else if (indexFunc == 2) { + res = log10(value); + } + else if (indexFunc == 3) { + res = log2(value); + } + else if (indexFunc == 4) { + res = log(value); + } + else if (indexFunc == 5) { + res = ceil(value); + } + else if (indexFunc == 6) { + res = floor(value); + } + else if (indexFunc == 7) { + res = round(value); + } + + return res; +} + +double ArithmeticEvaluator::evaluate() throw(int) { + QStack stack; + bool ok; + double value1,value2; + int index = 0; + QChar c; + foreach(QString elt, expression) { + c = elt.at(0); + /* CAUTION : + \x1bn, n must correspond to the order of QString in fctMarkers. + */ + if (c == '\x1b') { + value1 = stack.pop(); + elt.remove(0,1); + int idFunc = elt.toInt(&ok); + if ((!ok) || (idFunc < 0) || (idFunc >= fctMarkers.size())) throw(-index); + stack.push(evalFunction(idFunc,value1)); + } + else if (varMarkers.contains(c)) { + if (!varValues.contains(elt)) throw(-index); + stack.push(varValues.value(elt)); + } + else if (opMarkers.contains(c)) { + value2 = stack.pop(); + value1 = stack.pop(); + if (c == '+') { + stack.push(value1+value2); + } + else if (c == '-') { + stack.push(value1-value2); + } + else if (c == '*') { + stack.push(value1*value2); + } + else if (c == '/') { + stack.push(value1/value2); + } + } + else { + value1 = elt.toDouble(&ok); + if (!ok) throw(-index); + stack.push(value1); + } + index += 1; + } + + value1 = stack.pop(); + if (!stack.isEmpty()) throw(-1); + return value1; +} + +/* NOTE : + expr is of form: + ([ value1 | var1 | func1 | expr1 ] op1 [ value2 | var2 | func2 | expr2 ] op2 ... [ valuen | varn | funcn | exprn ]) + + Thus, if the whole expression does not end with ), we encapsulate it with ( ). + + If we don't consider priority among operators, then expression is converted into + A1 A2 op1 A3 op2 ... An opn-1 + + example : 1+2+3-4-5 -> 1 2 + 3 + 4 - + + If there is priority : * > / > + or - or func, then it is more complex + + example : 1+2+3/4*5-6 -> 1 2 + 3 4 5 * / + 6 - + + with parenthesis, we can do the same recursively + + example : 1+(2+3/4)*5-6 = 1 + expr1 * 5 - 6 -> 1 expr1 5 * + 6 - + but expr1 -> 2 3 4 / +, then we finally have 1 2 3 4 / + 5 * + 6 - + + a func is of form: + func_name(expr) + + example : ((1+3-sin(5/6))*(4+(7/3))) + + recursive cross in-depth of the expression leads to do a recursive call each time a ( is encountered. + Return of the recursive call is done when ) is encountered. + + */ + +void ArithmeticEvaluator::convert(const QString& _expression) throw(int) { + QString expr = _expression; + QString result=""; + expr.remove(QChar(' '), Qt::CaseInsensitive); + foreach(QString func, fctMarkers) { + QString rep = QString("\x1b%1").arg(fctMarkers.indexOf(QRegExp(func))); + + expr.replace(QRegExp(func),rep); + } + //cout << "packed expr: " << qPrintable(expr) << endl; + + int offset = 0; + try { + result = convertRecur(expr,&offset); + expression = result.split(","); + } + catch(int err) { + cerr << "error while recursive conversion: "; + throw(err); + } + +} + +QString ArithmeticEvaluator::convertRecur(const QString& _expression, int *offset) throw(int) { + QString result=""; + QStack pile; + + int size; + QChar c; + + QString number; + QString expr = _expression; + + // testing if it starts by a (,number, variable or function + if (!checkAfterOp(expr,*offset-1)) throw(*offset); + + // testing if it starts with a number + if ((expr[*offset] == '-') || (expr[*offset].isDigit())) { + number = getNumber(expr,*offset,&size); + result.append(number+","); + *offset += size; + } + // testing if it starts with a variable + else if (varMarkers.contains(expr[*offset])){ + number = getVariable(expr,*offset,&size); + result.append(number+","); + *offset += size; + } + + while (*offset= fctMarkers.size())) return -1; + return numFunc; +} + +bool ArithmeticEvaluator::checkAfterOp(const QString& _expression, int offset) { + int size; + if (offset+1 >= _expression.size()) return false; + + if (_expression[offset+1] == '(') return true; + else if (_expression[offset+1].isDigit()) return true; + else if (_expression[offset+1] == '-') { + if ((offset+2 < _expression.size()) && (_expression[offset+2].isDigit())) return true; + } + else if (varMarkers.contains(_expression[offset+1])) { + if ((offset+2 < _expression.size()) && (_expression[offset+2].isLetterOrNumber())) return true; + } + else if (getFunction(_expression, offset+1,&size) != -1) { + return true; + } + + return false; +} + +bool ArithmeticEvaluator::checkAfterPar(const QString& _expression, int offset) { + if (offset >= _expression.size()) return false; + // if ) is the last char of the expression : OK + if (offset == _expression.size()-1) return true; + + if (_expression[offset+1] == ')') return true; + else if (_expression[offset+1] == '+') return true; + else if (_expression[offset+1] == '-') return true; + else if (_expression[offset+1] == '*') return true; + else if (_expression[offset+1] == '/') return true; + + return false; +} diff --git a/ArithmeticEvaluator.h b/ArithmeticEvaluator.h new file mode 100644 index 0000000..f6d478b --- /dev/null +++ b/ArithmeticEvaluator.h @@ -0,0 +1,60 @@ +/*-==============================================================- + +file : ArithmeticEvaluator.h + +creation date : 19/05/2015 + +author : S. Domas (sdomas@univ-fcomte.fr) + +description : + +supp. infos : saved in UTF-8 [éè] + +-==============================================================-*/ +#ifndef __ARITHMETICEVALUATOR_H__ +#define __ARITHMETICEVALUATOR_H__ + +#include +#include + +#include + + +using namespace std; +using namespace Qt; + +class ArithmeticEvaluator { + +public: + + ArithmeticEvaluator(); + ArithmeticEvaluator(const QString& _expression) throw(int); + + void setExpression(const QString& _expression) throw(int); + inline void setVariablesValue(const QHash& _varValues) { varValues = _varValues; } + inline void setVariableValue(const QString& var, double value) { varValues.insert(var,value); } + inline void setVariableMarkers(const QString& _markers) { varMarkers = _markers; } + + void print(); + double evaluate() throw(int); + +protected: + QStringList expression; + QHash varValues; + QString varMarkers; // a sequence of symbols that are allowed to start a variable. $ is by default + QString opMarkers; // a sequence if symbols used as operators. +-*/ is the hard-coded default + QStringList fctMarkers; + + void convert(const QString& _expression) throw(int); + QString convertRecur(const QString& _expression, int* offset) throw(int); + QString getNumber(const QString& _expression, int offset, int *size); + QString getVariable(const QString& _expression, int offset, int *size); + int getFunction(const QString& _expression, int offset, int *size); + bool checkAfterOp(const QString& _expression, int offset); + bool checkAfterPar(const QString& _expression, int offset); + + double evalFunction(int indexFunc, double value); + +}; + +#endif //__ARITHMETICEVALUATOR_H__ diff --git a/BlockCategory.cpp b/BlockCategory.cpp new file mode 100644 index 0000000..0de4d86 --- /dev/null +++ b/BlockCategory.cpp @@ -0,0 +1,47 @@ +#include "BlockCategory.h" + +BlockCategory::BlockCategory(QString _name, int _id, BlockCategory* _parent) { + name = _name; + id = _id; + parent = _parent; +} + +void BlockCategory::addChild(BlockCategory* child) { + childs.append(child); +} + + + +BlockCategory* BlockCategory::getChild(QString name) { + QListIterator iter(childs); + BlockCategory* item = NULL; + while(iter.hasNext()) { + item = iter.next(); + if (item->name == name) return item; + } + return NULL; +} + +BlockCategory* BlockCategory::getChild(int index) { + if ((index >=0) && (index < childs.size()) ) { + return childs.at(index); + } + return NULL; +} + +QList BlockCategory::getAllChilds() +{ + return childs; +} + +ReferenceBlock *BlockCategory::getBlock(int index) { + if ((index >=0) && (index < blocks.size()) ) { + return blocks.at(index); + } + cout << "block null!" << endl; + return NULL; +} + +QDomElement BlockCategory::save(QDomDocument &doc) { +} + diff --git a/BlockCategory.h b/BlockCategory.h new file mode 100644 index 0000000..78f646e --- /dev/null +++ b/BlockCategory.h @@ -0,0 +1,50 @@ +#ifndef BLOCKCATEGORY_H +#define BLOCKCATEGORY_H + +#include + +#include +#include +#include "ReferenceBlock.h" +class ReferenceBlock; + +using namespace std; +using namespace Qt; + +class Block; + +class BlockCategory { + +public : + BlockCategory(QString _name, int _id, BlockCategory* _parent = NULL); + int id; + // getters + inline int getId() { return id; } + inline QString getName() { return name; } + inline BlockCategory* getParent() { return parent; } + inline QList getChilds() { return childs; } + BlockCategory* getChild(QString name); + BlockCategory* getChild(int index); + QList getAllChilds(); + inline QList getBlocks() { return blocks; } + ReferenceBlock *getBlock(int index); + + // setters + void addChild(BlockCategory* child); + inline void setParent(BlockCategory* _parent) { parent = _parent; } + + // I/O + QDomElement save(QDomDocument &doc); + + BlockCategory *getRoot(); + + //int id; + QList childs; + BlockCategory* parent; + QList blocks; +private: + QString name; + +}; + +#endif // BLOCKCATEGORY_H diff --git a/BlockImplementation.cpp b/BlockImplementation.cpp new file mode 100644 index 0000000..571b72b --- /dev/null +++ b/BlockImplementation.cpp @@ -0,0 +1,560 @@ +#include "BlockImplementation.h" + +#include "FunctionalBlock.h" +#include "ReferenceBlock.h" +#include "ReferenceInterface.h" +#include "FunctionalInterface.h" +#include "BlockParameter.h" + + +BlockImplementation::BlockImplementation(const QString& _xmlFile) { + xmlFile = _xmlFile; + + evaluator = new ArithmeticEvaluator; + evaluator->setVariableMarkers("@$"); +} + +BlockImplementation::BlockImplementation(const QString& _xmlFile, const QString &_referenceXml, const QString &_referenceMd5) { + xmlFile = _xmlFile; + referenceXml = _referenceXml; + referenceMd5 = _referenceMd5; +} + +void BlockImplementation::generateVHDL(FunctionalBlock* _block, const QString &path) throw(Exception) { + + block = _block; + + QFile implFile(xmlFile); + + // reading in into QDomDocument + QDomDocument document("implFile"); + + if (!implFile.open(QIODevice::ReadOnly)) { + throw(Exception(IMPLFILE_NOACCESS)); + } + if (!document.setContent(&implFile)) { + implFile.close(); + throw(Exception(IMPLFILE_NOACCESS)); + } + implFile.close(); + + bool genController = false; + QString coreFile = ""; + QString controllerFile = ""; + + if (reference->isWBConfigurable()) { + genController = true; + controllerFile = path; + controllerFile.append(block->getName()); + controllerFile.append("_ctrl.vhd"); + } + else { + controllerFile = "nofile.vhd"; + } + coreFile = path; + coreFile.append(block->getName()); + coreFile.append(".vhd"); + + QFile vhdlCore(coreFile); + QFile vhdlController(controllerFile); + + if (!vhdlCore.open(QIODevice::WriteOnly)) { + throw(Exception(VHDLFILE_NOACCESS)); + } + + if (genController) { + if (!vhdlController.open(QIODevice::WriteOnly)) { + throw(Exception(VHDLFILE_NOACCESS)); + } + } + QTextStream outCore(&vhdlCore); + QTextStream outController; + if (genController) { + outController.setDevice(&vhdlController); + } + + try { + + + //Get the root element + QDomElement impl = document.documentElement(); + QDomElement eltComments = impl.firstChildElement("comments"); + generateComments(eltComments, coreFile, outCore); + QDomElement eltLibs = eltComments.nextSiblingElement("libraries"); + generateLibraries(eltLibs, outCore); + generateEntity(outCore, genController); + QDomElement eltArch = eltLibs.nextSiblingElement("architecture"); + generateArchitecture(eltArch, outCore); + if (genController) { + generateController(outController); + } + } + catch(Exception err) { + throw(err); + } + + vhdlCore.close(); + vhdlController.close(); +} + +// This function generates the comments part of the VHDL document +void BlockImplementation::generateComments(QDomElement &elt, QString coreFile, QTextStream& out) throw(Exception) { + + for(int i = 0; i < 50; i++) { + out << "--"; + } + out << "\n--\n"; + QString fileName = coreFile; + out << "-- File : " << fileName << "\n"; + out << "--\n"; + QDomElement eltAuthor = elt.firstChildElement("author"); + QString firstName = eltAuthor.attribute("firstname",""); + QString lastName = eltAuthor.attribute("lastname",""); + QString mail = eltAuthor.attribute("mail",""); + out << "-- Author(s) : "<getName(); + //QList listParams = reference->getParameters(); + QList listInputs = reference->getInputs(); + QList listOutputs = reference->getOutputs(); + QList listBidirs = reference->getBidirs(); + QString typePort, namePort; + + out << "entity " << nameEnt << " is\n"; + + + /* TODO : rewrite the generation to take into acocunt the new object hierarchy */ + + // Generation of the generics + QList listGenerics = reference->getGenericParameters(); + if ((!listGenerics.isEmpty()) || (hasController)) { + out << " generic (" << endl; + if (hasController) { + out << " wb_data_width : integer = 16;" << endl; + out << " wb_addr_width : integer = 12"; + if (!listGenerics.isEmpty()) out << ";"; + out << endl; + } + for(i=0;itoVHDL(BlockParameter::Entity, 0); + } + out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma); + + out << " );" << endl; + } + + out << " port (" << endl; + + // Generation of the clk & rst signals + out << " -- clk/rst" << endl; + for(int i = 0; i < listInputs.size(); i++) { + if(listInputs.at(i)->getPurpose() == AbstractInterface::Clock || listInputs.at(i)->getPurpose() == AbstractInterface::Reset) { + out << " " << listInputs.at(i)->getName() << " : in std_logic;" << endl; + } + } + + if (hasController) { + // Generation of the wishbone signals + out << " -- registers r/w via wishbone" << endl; + QList listWB = reference->getWishboneParameters(); + for(i=0;itoVHDL(BlockParameter::Entity, 0); + } + out << " " << listWB.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma); + } + + + // Generation of the data signals + out << "-- data ports\n"; + for(int i = 0; i < listInputs.size(); i++) { + namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listInputs.at(i)->getName())); + if(listInputs.at(i)->getWidth().compare("1")) + typePort = "std_logic"; + else + typePort = calculateWidth(listInputs.at(i)->getWidth()); + if(listInputs.at(i)->getPurpose() == 1) + out << namePort << " : in std_logic_vector(" << typePort << " -1 downto 0) ;\n"; + } + + for(int i = 0; i < listOutputs.size(); i++) { + namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listOutputs.at(i)->getName())); + if(listOutputs.at(i)->getWidth().compare("1")) + typePort = "std_logic"; + else + typePort = calculateWidth(listOutputs.at(i)->getWidth()); + if(listOutputs.at(i)->getPurpose() == 1) + out << namePort << " : out std_logic_vector(" << typePort << " -1 downto 0) ;\n"; + } + + for(int i = 0; i < listBidirs.size(); i++) { + namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listBidirs.at(i)->getName())); + if(listBidirs.at(i)->getWidth().compare(("1"))) + typePort = "std_logic"; + else + typePort = calculateWidth((listBidirs.at(i)->getWidth())); + if(listBidirs.at(i)->getPurpose() == 1) + out << namePort << " : inout std_logic_vector(" << typePort << " -1 downto 0) ;\n"; + } +} + +// This function generates the architecture part of the VHDL document +void BlockImplementation::generateArchitecture(QDomElement &elt, QTextStream& out) throw(Exception) { + + QString expr; + QDomElement eltArch = elt.nextSiblingElement("architecture"); + out << "architecture " << nameEnt <<"_1 of " << nameEnt << "is\n"; + QString implText = eltArch.text(); + QStringList listLine = implText.split("\n"); + for(int i =0; i < listLine.size(); i++) { + if(listLine.at(i).contains(QRegularExpression("@foreach{")) != -1) { + while(listLine.at(i).compare("@endforeach") != -1) { + expr = expr + listLine.at(i) + '\n'; + i++; + } + expr = expr + listLine.at(i); + out << evalComplex(expr, 1) << '\n'; + } + if(listLine.at(i).contains(QRegularExpression("@caseeach{")) != -1) { + while(listLine.at(i).compare("@endcaseeach") != -1) { + expr = expr + listLine.at(i) + '\n'; + i++; + } + expr = expr + listLine.at(i); + out << evalComplex(expr, 2) << '\n'; + } + + if(listLine.at(i).contains('@') == -1) + out << listLine.at(i) << "\n"; + else + out << eval(listLine.at(i), out) << "\n"; + } +} + +void BlockImplementation::generateController(QTextStream &out) throw(Exception) { +} + +QString BlockImplementation::eval(QString line, QTextStream& out) { + QString res, s, begLine, endLine, expr; + evaluator->setExpression(line); + QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)"); + QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)"); + QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*"); + + int nbAt = line.count('@'); + while(nbAt != 0) { + for(int i = 0; i < line.size(); i++) { + if(rxString->indexIn(line)) { + begLine = rxString->cap(1); + s = rxString->cap(2); + endLine = rxString->cap(3); + res = begLine + evalString(s) + endLine + '\n'; + nbAt --; + } + } + for(int i = 0; i < line.size(); i++) { + if(rxValue->indexIn(line)) { + begLine = rxValue->cap(1); + s = rxValue->cap(2); + endLine = rxValue->cap(3); + res = begLine + evalValue(s) + endLine + '\n'; + nbAt --; + } + } + for(int i = 0; i < line.size(); i++) { + if(rxExpr->indexIn(line)) { + expr = rxExpr->cap(1); + if(expr.count('@') == 0) { + evaluator->setExpression(expr); + s = QString::number(evaluator->evaluate()); + } + res = begLine + s + endLine + '\n'; + nbAt --; + } + } + } + return res; +} + +QString BlockImplementation::evalComplex(QString line, int id) { + QString res, s, begLine, endLine, expr; + QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)"); + QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)"); + QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*"); + QRegExp *rxFor = new QRegExp("@foreach{.*}(@{.*})(.*)@endforeach"); + QRegExp *rxCase = new QRegExp("@caseeach{.*,(.*),(.*)}(@{.*})(.*)@endcaseeach"); + QRegExp *rxCaseDown = new QRegExp("@#-:(.*)"); + QRegExp *rxCaseUp = new QRegExp("@#:(.*)"); + evaluator->setExpression(line); + + int nbAt = line.count('@') - 2; + while(nbAt != 0) { + for(int i = 0; i < line.size(); i++) { + if(rxString->indexIn(line)) { + begLine = rxString->cap(1); + s = rxString->cap(2); + endLine = rxString->cap(3); + if(evalStringComplex(s)->size() == 0) + line = begLine + evalString(s) + endLine; + nbAt --; + } + } + for(int i = 0; i < line.size(); i++) { + if(rxValue->indexIn(line)) { + begLine = rxValue->cap(1); + s = rxValue->cap(2); + endLine = rxValue->cap(3); + line = begLine + evalValue(s) + endLine; + nbAt --; + } + } + for(int i = 0; i < line.size(); i++) { + if(rxExpr->indexIn(line)) { + expr = rxExpr->cap(1); + if(expr.count('@') == 0) { + evaluator->setExpression(expr); + s = QString::number(evaluator->evaluate()); + } + res = begLine + s + endLine + '\n'; + nbAt --; + } + } + } + + if(id == 1) { + if(rxFor->indexIn(line)) { + QString intName, instruc; + intName = rxFor->cap(1); + instruc = rxFor->cap(2); + QList *intList = evalStringComplex(intName); + if(intList->size() != 0) { + for(int i = 0; i < intList->size(); i++) { + res = intList->at(i)->getName() + instruc + '\n'; + } + } + } + } + + else if(id == 2) { + if(rxCase->indexIn(line)) { + QString intName, sigName, cases, instruc; + int number; + sigName = rxCase->cap(1); + cases = rxCase->cap(2); + intName = rxCase->cap(3); + instruc = rxCase->cap(4); + QList *intList = evalStringComplex(intName); + int listSize = intList->count(); + res = "case " + sigName + " is\n"; + if(rxCaseUp->indexIn(cases)) { + number = rxCaseUp->cap(1).toInt(); + for(int j = number; j < listSize; j++) { + if(listSize > 0) { + for(int i = 0; i < listSize; i++) { + res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n"; + } + } + else + res += "\twhen " + number + ' ' + intName + instruc + "\n"; + number++; + } + } + if(rxCaseDown->indexIn(cases)) { + number = rxCaseDown->cap(1).toInt(); + for(int j = number; j < listSize; j++) { + if(listSize > 0) { + for(int i = 0; i < listSize; i++) { + res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n"; + } + } + else + res += "\twhen " + number + ' ' + intName + instruc + "\n"; + number--; + } + res += "end case ;\n"; + } + } + } + return res; +} + +QString BlockImplementation::evalString(QString s) { + + QString name = getIfaceUserName(block->AbstractBlock::getIfaceFromName(s)); + return name; +} + +QList* BlockImplementation::evalStringComplex(QString s) { + + int j = 0; + QList *listInterfaces = new QList(); + AbstractInterface *inter = block->AbstractBlock::getIfaceFromName(s); + QList listIntBlock = block->getInterfaces(); + for(int i = 0; i < listIntBlock.size(); i++) { + if(inter->getName().compare(listIntBlock.at(i)->getName()) < -1) { + listInterfaces->insert(j, inter); + j ++; + } + } + return listInterfaces; +} + +QString BlockImplementation::evalValue(QString s) { + + QString val = ""; + if(paramMap.contains(s)) + val = paramMap.value(s); + return val; +} + +QString BlockImplementation::getIfaceUserName(AbstractInterface* refIface) { + + if (! refIface->isReferenceInterface()) return ""; + + AbstractInterface* funcIface = NULL; + + if (refIface->getDirection() == AbstractInterface::Input) { + foreach(AbstractInterface* iface, block->getInputs()) { + FunctionalInterface* fi = (FunctionalInterface*)iface; + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } + } + else if (refIface->getDirection() == AbstractInterface::Output) { + foreach(AbstractInterface* iface, block->getOutputs()) { + FunctionalInterface* fi = (FunctionalInterface*)iface; + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } + } + else if (refIface->getDirection() == AbstractInterface::InOut) { + foreach(AbstractInterface* iface, block->getBidirs()) { + FunctionalInterface* fi = (FunctionalInterface*)iface; + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } + } + if (funcIface == NULL) return ""; + + return funcIface->getName(); +} + +QDataStream& operator<<(QDataStream &out, const BlockImplementation &impl) { + + out.setVersion(QDataStream::Qt_5_0); + + QByteArray blockData; + QDataStream toWrite(&blockData, QIODevice::WriteOnly); + + toWrite << impl.xmlFile; + toWrite << impl.referenceXml; + toWrite << impl.referenceMd5; + + out << blockData; + + return out; +} + +QDataStream& operator>>(QDataStream &in, BlockImplementation &impl) { + + quint32 blockSize; + + in.setVersion(QDataStream::Qt_5_0); + + in >> blockSize; + + in >> impl.xmlFile; + in >> impl.referenceXml; + in >> impl.referenceMd5; + + return in; +} + +QString BlockImplementation::calculateWidth(QString s){ + QRegExp *rxWidth = new QRegExp("$*([a-zA-Z0-9_-]*)"); + QStringList matchList = s.split(" "); + int pos = 0; + QString res, line; + QList listParams = reference->getParameters(); + + while ((pos = rxWidth->indexIn(s, pos)) != -1) { + matchList << rxWidth->cap(1); + pos += rxWidth->matchedLength(); + } + + for (int i = 0; i < matchList.size(); i++) { + QString match = matchList.at(i); + if(rxWidth->indexIn(match)) { + for(int j = 0; j < listParams.size(); j++) { + if(match.compare(listParams.at(j)->getName())) { + BlockParameter *param = listParams.at(i); + if(param->getContext() == "generic") { + match = match.remove('$'); + } + else { + match = param->getValue().toString(); + } + } + } + } + } + line = matchList.join(' '); + evaluator->setExpression(line); + res = evaluator->evaluate(); + return res; +} + diff --git a/BlockImplementation.h b/BlockImplementation.h new file mode 100644 index 0000000..df0e499 --- /dev/null +++ b/BlockImplementation.h @@ -0,0 +1,68 @@ +#ifndef __BLOCKIMPLEMENTATION_H__ +#define __BLOCKIMPLEMENTATION_H__ + +#include +#include + +#include +#include + +class ReferenceBlock; +class FunctionalBlock; +class AbstractInterface; + +#include "ArithmeticEvaluator.h" +class ArithmeticEvaluator; + +#include "Exception.h" +class Exception; + + +using namespace std; +using namespace Qt; + +class BlockImplementation { + +public: + + BlockImplementation(const QString& _xmlFile); + BlockImplementation(const QString& _xmlFile, const QString& _referenceXml, const QString& _referenceMd5); + + inline QString getXmlFile() { return xmlFile; } + inline QString getReferenceXml() { return referenceXml; } + inline QString getReferenceMd5() { return referenceMd5; } + QString eval(QString line, QTextStream& out); + QString evalComplex(QString line, int num); + QString evalString(QString s); + QList* evalStringComplex(QString s); + QString evalValue(QString s); + QString calculateWidth(QString s); + + inline void setReference(ReferenceBlock* _reference) { reference = _reference; } + + void generateVHDL(FunctionalBlock* _block, const QString& path) throw(Exception); // main entry to generate the VHDL code + +private: + QString xmlFile; + QString referenceXml; + QString referenceMd5; + QString nameEnt, line; + QMap paramMap; + ArithmeticEvaluator* evaluator; + ReferenceBlock* reference; + FunctionalBlock* block; // the current functional block for which this implementation is used. + + void generateComments(QDomElement &elt,QString coreFile, QTextStream& out) throw(Exception); // generates comments from element + void generateLibraries(QDomElement &elt, QTextStream& out) throw(Exception); // generates libraries from element + void generateEntity(QTextStream& out, bool hasController=false) throw(Exception); // generate the entity using reference + void generateArchitecture(QDomElement &elt, QTextStream& out) throw(Exception); // generate the architecture using element + void generateController(QTextStream& out) throw(Exception); // generate the wishbone controller of the block + + QString getIfaceUserName(AbstractInterface* refIface); // get the name of an interface given by the user, from the reference interface + + friend QDataStream &operator<<(QDataStream &out, const BlockImplementation &impl); + friend QDataStream &operator>>(QDataStream &in, BlockImplementation &impl); +}; + +#endif // __BLOCKIMPLEMENTATION_H__ + diff --git a/BlockLibraryTree.cpp b/BlockLibraryTree.cpp new file mode 100644 index 0000000..33980f9 --- /dev/null +++ b/BlockLibraryTree.cpp @@ -0,0 +1,137 @@ +#include "BlockLibraryTree.h" + +BlockLibraryTree::BlockLibraryTree() { + tabCategories = NULL; + tabIdParent = NULL; + nbCategories = 0; +} + +BlockLibraryTree::~BlockLibraryTree() { + clear(); +} + +void BlockLibraryTree::clear() { + + for(int i=0;iblocks.clear(); + } +} + +void BlockLibraryTree::addItem(QXmlAttributes &attributes) +{ + nbCategories++; + if(tabCategories == NULL){ + tabCategories = new BlockCategory* [1]; + tabIdParent = new int[1]; + } + else{ + BlockCategory** tmpTabCat = new BlockCategory* [nbCategories]; + int* tmpTabParent = new int[nbCategories]; + for(int i=0; i< nbCategories; i++){ + tmpTabCat[i] = tabCategories[i]; + tmpTabParent[i] = tabIdParent[i]; + } + tabCategories = tmpTabCat; + tabIdParent = tmpTabParent; + } + + QString name = attributes.value(0); + int id = attributes.value(1).toInt(); + int idParent = attributes.value(2).toInt(); + BlockCategory* cat = new BlockCategory(name,id); + tabCategories[id] = cat; + tabIdParent[id] = idParent; +} + +bool BlockLibraryTree::initChildParent() +{ + // initializing parent/childs + for(int i=0;i= nbCategories) return false; + tabCategories[i]->setParent(tabCategories[tabIdParent[i]]); + tabCategories[tabIdParent[i]]->addChild(tabCategories[i]); + } + } + return true; +} + + +QDomElement BlockLibraryTree::save(QDomDocument &doc) { + +} + +/* NOTE : load() is the only way to initialize the tree. + It is done at the begining of the application, while reading + the configuration file. + elt MUST be the DOM element that corresponds to the tag + */ +void BlockLibraryTree::load(QDomElement &elt) throw(Exception) { + + if (elt.tagName() != "categories") throw(Exception(CONFIGFILE_CORRUPTED)); + + QString nbStr = elt.attribute("nb","none"); + bool ok; + int nb = nbStr.toInt(&ok); + QDomNodeList list = elt.elementsByTagName("category"); + nbCategories = list.size(); + if (nb != nbCategories) throw(Exception(CONFIGFILE_CORRUPTED)); + QString name; + int id; + QString idStr; + int idParent; + QString idParentStr; + + tabCategories = new BlockCategory* [nbCategories]; + tabIdParent = new int[nbCategories]; + BlockCategory* cat = NULL; + + // creating all BlockCategory objects + for(int i=0;i= nbCategories)) throw(Exception(CONFIGFILE_CORRUPTED)); + idParent = idParentStr.toInt(&ok); + if ((!ok)|| (idParent < -1) || (idParent >= nbCategories)) throw(Exception(CONFIGFILE_CORRUPTED)); + cat = new BlockCategory(name,id); + tabCategories[id] = cat; + tabIdParent[id] = idParent; + } + + ok = initChildParent(); + delete [] tabIdParent; + if (!ok) throw(Exception(CONFIGFILE_CORRUPTED)); +} + +BlockCategory* BlockLibraryTree::searchCategory(int id) { + + if (tabCategories != NULL) { + if ((id>=0) && (id < nbCategories)) { + return tabCategories[id]; + } + } + + return NULL; +} + +BlockCategory *BlockLibraryTree::getRoot() { + if (tabCategories != NULL) { + if (nbCategories > 0) { + return tabCategories[0]; + } + } + return NULL; +} diff --git a/BlockLibraryTree.h b/BlockLibraryTree.h new file mode 100644 index 0000000..f8fa60c --- /dev/null +++ b/BlockLibraryTree.h @@ -0,0 +1,50 @@ +#ifndef __BLOCKLIBRARYTREE_H__ +#define __BLOCKLIBRARYTREE_H__ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "BlockCategory.h" +#include "Exception.h" + +using namespace std; +using namespace Qt; +class BlockCategory; +class BlockLibraryTree { + +public : + BlockLibraryTree(); + ~BlockLibraryTree(); + + void clear(); // free thewhole tree + void clearBlocks(); // just remove the blocks from the BlockCateogry lists + void addItem(QXmlAttributes &attributes); + bool initChildParent(); + + BlockCategory *getRoot(); + BlockCategory *searchCategory(int id); + + QDomElement save(QDomDocument &doc); + void load(QDomElement &elt) throw(Exception); +private: + /* NOTE : + This class builds a tree of BlockCategory, but it also stores all BlockCategory object + in an array so that access via an id is direct. + + The root of the tree is in fact tabCategories[0] + */ + BlockCategory** tabCategories; + int* tabIdParent; + int nbCategories; + +}; + + +#endif // BLOCKLIBRARYTREE_H diff --git a/BlockLibraryWidget.cpp b/BlockLibraryWidget.cpp new file mode 100644 index 0000000..0aa9ed1 --- /dev/null +++ b/BlockLibraryWidget.cpp @@ -0,0 +1,107 @@ +#include "BlockLibraryWidget.h" +#include "BlockLibraryTree.h" + +BlockLibraryWidget::BlockLibraryWidget(Dispatcher* _dispatcher, + Parameters* _params, + QWidget *parent) : QWidget(parent) { + + + dispatcher = _dispatcher; + params = _params; + + // creating the widget : tree, buttons, ... + layout = new QBoxLayout(QBoxLayout::TopToBottom, this); + tree = new QTreeWidget(this); + buttonAdd = new QPushButton("add", this); + buttonAdd->setEnabled(false); + + connect(tree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(clicked())); + connect(tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(doubleClicked())); + connect(buttonAdd, SIGNAL(clicked()), this, SLOT(addClicked())); + + BlockCategory* cat = params->categoryTree->searchCategory(0); + + QTreeWidgetItem* item = tree->invisibleRootItem(); + tree->setHeaderLabel("Blocks list"); + + + addChild(cat,item); + + layout->addWidget(tree); + layout->addWidget(buttonAdd); + this->setLayout(layout); + + this->setFixedSize(300,230); +} + + +BlockLibraryWidget::~BlockLibraryWidget() { +} + +void BlockLibraryWidget::addChild(BlockCategory *catParent,QTreeWidgetItem* itemParent) { + + QTreeWidgetItem* newItemCat = NULL; + QTreeWidgetItem* newItemBlock = NULL; + + QList childs = catParent->getAllChilds(); + foreach(BlockCategory* cat, childs){ + newItemCat = new QTreeWidgetItem(itemParent); + newItemCat->setData(0,Qt::DisplayRole, cat->getName()); + QList list = cat->getBlocks(); + for(int i=0; isetData(0,Qt::DisplayRole, list.at(i)->getName()); + newItemBlock->setData(1,Qt::DisplayRole, cat->getId()); + newItemBlock->setData(2,Qt::DisplayRole, i); + newItemBlock->setIcon(0,QIcon("icons/window_new.png")); + } + addChild(cat,newItemCat); + } + /* TO DO : + - getting the childs of catParent + - for each BlockCategory cat of that list : + - create an new TreeWidgetItem (newImteCat), with itemParent as a parent + - set the first column of that item with the categry name + - get the list of the blocks that are associated with cat + - for i = 0 to that list size. + - create a new TreeWidgetItem (newItemBlock), with newItemCat as a parent + - set the first column of that item with the block name + - set the second column of that item with the newItemCat id + - set the third column of that item with the value of i + - endfor + - call again addChild with cat and newImteCat as parameters + - end for + */ +} + + +void BlockLibraryWidget::addClicked() { + + QTreeWidgetItem *item = tree->selectedItems().at(0); + if(item->data(1,Qt::DisplayRole).isValid() && item->data(2,Qt::DisplayRole).isValid()){ + int idParent = item->data(1,Qt::DisplayRole).toInt(); + int idBlock = item->data(2,Qt::DisplayRole).toInt(); + dispatcher->addBlock(idParent, idBlock); + } + + // only take the first selected + // retrieve id of category and id of block + // calling dispatcher addBlock() method. +} + + +void BlockLibraryWidget::clicked() +{ + if(tree->selectedItems().length() > 0){ + QTreeWidgetItem *item = tree->selectedItems().at(0); + if(item->data(1,Qt::DisplayRole).isValid()) + buttonAdd->setEnabled(true); + else + buttonAdd->setEnabled(false); + } +} + +void BlockLibraryWidget::doubleClicked() +{ + addClicked(); +} diff --git a/BlockLibraryWidget.h b/BlockLibraryWidget.h new file mode 100644 index 0000000..f07be4d --- /dev/null +++ b/BlockLibraryWidget.h @@ -0,0 +1,45 @@ +#ifndef __BLOCKLIBRARYWIDGET_H__ +#define __BLOCKLIBRARYWIDGET_H__ + +#include + +#include +#include + +#include "Dispatcher.h" +class Dispatcher; +#include "Parameters.h" +class Parameters; +#include "BlockCategory.h" +class BlockCategory; + +using namespace std; +using namespace Qt; + +class BlockLibraryWidget : public QWidget { + Q_OBJECT + +public: + explicit BlockLibraryWidget(Dispatcher* _dispatcher, Parameters* _params, QWidget *parent = 0); + ~BlockLibraryWidget(); + +private slots: + void addClicked(); + void clicked(); + void doubleClicked(); + + +private: + Parameters* params; + Dispatcher* dispatcher; + QTreeWidget* tree; + QPushButton* buttonAdd; + QBoxLayout *layout; + // other attributes + + void addChild(BlockCategory *catParent, QTreeWidgetItem* itemParent); + void addButtons(); + +}; + +#endif // __BLOCKLIBRARYWIDGET_H__ diff --git a/BlockParameter.cpp b/BlockParameter.cpp new file mode 100644 index 0000000..f8dfcd7 --- /dev/null +++ b/BlockParameter.cpp @@ -0,0 +1,121 @@ +#include "BlockParameter.h" + +BlockParameter::BlockParameter() { + owner = NULL; + name = ""; + type = BlockParameter::String; + defaultValue = QVariant(); +} + +BlockParameter::BlockParameter(AbstractBlock* _owner, const QString &_name, const QString &_type, const QString &_value) { + owner = _owner; + name =_name; + type = typeFromString(_type); + defaultValue = QVariant(_value); +} + +BlockParameter::~BlockParameter(){ + +} + +QVariant BlockParameter::getValue() { + return defaultValue; +} + +bool BlockParameter::isUserParameter() { + return false; + +} + +bool BlockParameter::isGenericParameter() { + return false; +} + +bool BlockParameter::isWishboneParameter() { + return false; +} + +bool BlockParameter::isPortParameter() { + return false; +} + +void BlockParameter::setValue(const QString& _value) { + defaultValue = QVariant(_value); +} + +bool BlockParameter::isValueSet() { + if (defaultValue.isNull()) return false; + return true; +} + +QString BlockParameter::toVHDL(int context, int flags) { + + QString ret=""; + return ret; +} + +QString BlockParameter::getTypeString() { + if (type == BlockParameter::Bit) { + return "bit"; + } + else if (type == BlockParameter::BitVector) { + return "bit_vector"; + } + else if (type == BlockParameter::Boolean) { + return "boolean"; + } + else if (type == BlockParameter::Integer) { + return "integer"; + } + else if (type == BlockParameter::Natural) { + return "natural"; + } + else if (type == BlockParameter::Positive) { + return "positive"; + } + else if (type == BlockParameter::Real) { + return "real"; + } + else if (type == BlockParameter::Character) { + return "character"; + } + else if (type == BlockParameter::String) { + return "string"; + } + else if (type == BlockParameter::Time) { + return "time"; + } + return "undefined"; +} + +int BlockParameter::typeFromString(const QString &_type) { + int ret = BlockParameter::Expression; + + if (_type == "string") { + ret = BlockParameter::String; + } + else if (_type == "expression") { + ret = BlockParameter::Expression; + } + else if (_type == "boolean") { + ret = BlockParameter::Boolean; + } + else if (_type == "integer") { + ret = BlockParameter::Integer; + } + else if (_type == "natural") { + ret = BlockParameter::Natural; + } + else if (_type == "positive") { + ret = BlockParameter::Positive; + } + else if (_type == "real") { + ret = BlockParameter::Real; + } + else if (_type == "time") { + ret = BlockParameter::Time; + } + return ret; +} + + diff --git a/BlockParameter.h b/BlockParameter.h new file mode 100644 index 0000000..e0c4af2 --- /dev/null +++ b/BlockParameter.h @@ -0,0 +1,68 @@ +#ifndef __BLOCKPARAMETER_H__ +#define __BLOCKPARAMETER_H__ + +#include +#include + +#include + +#include "AbstractBlock.h" +class AbstractBlock; + +using namespace std; +using namespace Qt; + + +class BlockParameter { + +public : + + enum ParamType { Expression = 1, Character, String, Bit, BitVector, Boolean, Integer, Natural, Positive, Real, Time}; + // a bit ugly to put that here but more practical for using them + enum ParamWBAccess { Read = 1, Write = 2}; + enum ParamWBDuration { Permanent = 1, Trigger = 2 }; + enum ParamVHDLContext { Entity = 1, Component = 2, Architecture = 3 }; // NB : 3 is when creating an instance of the block that owns this iface + enum ParamVHDLFlags { NoComma = 1 }; + + BlockParameter(); + BlockParameter(AbstractBlock* _owner, const QString& _name , const QString& _type, const QString& _value); + + virtual ~BlockParameter(); + + // getters + inline AbstractBlock* getOwner() { return owner; } + inline QString getName() { return name; } + inline int getType() { return type; } + QString getTypeString(); + virtual QVariant getValue(); // may be overriden + virtual QString getContext() = 0; + + // setters + inline void setOwner(AbstractBlock* _owner) { owner = _owner; } + inline void setName(const QString& _name) { name = _name; } + inline void setType(int _type) { type = _type; } + virtual void setValue(const QString& _value); + + // testers + virtual bool isValueSet(); // may be overridden for User and Generic parameters + virtual bool isUserParameter(); + virtual bool isGenericParameter(); + virtual bool isWishboneParameter(); + virtual bool isPortParameter(); + + // others + virtual BlockParameter* clone() = 0; + virtual QString toVHDL(int context, int flags); + int typeFromString(const QString& _type); + +protected: + + AbstractBlock* owner; + QString name; + int type; + QVariant defaultValue; // the value set during construction + +}; + +#endif // __BLOCKPARAMETER_H__ + diff --git a/BlockParameterGeneric.cpp b/BlockParameterGeneric.cpp new file mode 100644 index 0000000..5b15eb9 --- /dev/null +++ b/BlockParameterGeneric.cpp @@ -0,0 +1,97 @@ +#include "BlockParameterGeneric.h" +#include "GroupBlock.h" +#include "FunctionalBlock.h" + +BlockParameterGeneric::BlockParameterGeneric() : BlockParameter() { + userValue = defaultValue; +} + +BlockParameterGeneric::BlockParameterGeneric(AbstractBlock* _owner, const QString &_name, const QString &_type, const QString &_value) : BlockParameter(_owner, _name, _type, _value) { + userValue = defaultValue; +} + +QVariant BlockParameterGeneric::getValue() { + if (isValueSet()) { + return userValue; + } + return defaultValue; +} + +bool BlockParameterGeneric::isGenericParameter() { + return true; +} + +void BlockParameterGeneric::setValue(const QString& _value) { + userValue = QVariant(_value); +} + + +bool BlockParameterGeneric::isValueSet() { + if (userValue.isNull()) return false; + return true; +} + +bool BlockParameterGeneric::isDefaultValue() { + if (userValue == defaultValue) return true; + return false; +} + +BlockParameter* BlockParameterGeneric::clone() { + + BlockParameter* block = new BlockParameterGeneric(owner,name,getTypeString(),defaultValue.toString()); + return block; +} + +QString BlockParameterGeneric::toVHDL(int context, int flags) { + + QString ret=""; + + + if ((context == BlockParameter::Entity) || (context == BlockParameter::Component)) { + + QString formatValue = "%1 : %2 := %3"; + QString formatNoValue = "%1 : %2"; + if ((flags & BlockParameter::NoComma) == 0) { + formatValue.append(";"); + formatNoValue.append(";"); + } + + if (!userValue.isNull()) { + ret = formatValue.arg(name).arg(type).arg(userValue.toString()); + } + else if (!defaultValue.isNull()) { + ret = formatValue.arg(name).arg(type).arg(defaultValue.toString()); + } + else { + ret = formatNoValue.arg(name).arg(type); + } + } + else if (context == BlockParameter::Architecture) { + QString format = "%1 => %2"; + if ((flags & BlockParameter::NoComma) == 0) { + format.append(";"); + } + AbstractBlock* parent = owner->getParent(); + BlockParameter* p = parent->getParameterFromName(name); + if (p != NULL) { + /* the parent group has a generic parameter with the same + name + */ + ret = format.arg(name).arg(name); + } + else { + if (!userValue.isNull()) { + ret = format.arg(name).arg(userValue.toString()); + } + else if (!defaultValue.isNull()) { + ret = format.arg(name).arg(defaultValue.toString()); + } + else { + // abnormal case + ret = format.arg(name).arg("INVALID_VALUE"); + } + } + } + return ret; +} + diff --git a/BlockParameterGeneric.h b/BlockParameterGeneric.h new file mode 100644 index 0000000..9fb81a6 --- /dev/null +++ b/BlockParameterGeneric.h @@ -0,0 +1,46 @@ +#ifndef __BLOCKPARAMETERGENERIC_H__ +#define __BLOCKPARAMETERGENERIC_H__ + +#include +#include + +#include + +#include "BlockParameter.h" +class BlockParameter; + +using namespace std; +using namespace Qt; + + +class BlockParameterGeneric : public BlockParameter { + +public : + + BlockParameterGeneric(); + BlockParameterGeneric(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _value); + + // getters + QVariant getValue(); + inline QString getContext() { return "generic";} + // setters + void setValue(const QString& _value); + inline void resetToDefaultValue() { userValue = defaultValue; } + + // testers + bool isValueSet(); + bool isDefaultValue(); + bool isGenericParameter(); + + // others + BlockParameter* clone(); + QString toVHDL(int context, int flags); + +private: + + QVariant userValue; + +}; + +#endif // __BLOCKPARAMETERGENERIC_H__ + diff --git a/BlockParameterPort.cpp b/BlockParameterPort.cpp new file mode 100644 index 0000000..c33724b --- /dev/null +++ b/BlockParameterPort.cpp @@ -0,0 +1,58 @@ +#include "BlockParameterPort.h" +#include "ArithmeticEvaluator.h" +#include "FunctionalBlock.h" +#include "FunctionalInterface.h" + +BlockParameterPort::BlockParameterPort() : BlockParameter() { + ifaceName = ""; +} + +BlockParameterPort::BlockParameterPort(AbstractBlock* _owner, const QString &_name, const QString &_value, const QString &_ifaceName) : BlockParameter(_owner, _name, "expression", _value) { + ifaceName = _ifaceName; +} + +bool BlockParameterPort::isPortParameter() { + return true; +} + +BlockParameter* BlockParameterPort::clone() { + BlockParameter* block = new BlockParameterPort(owner,name,defaultValue.toString(),ifaceName); + return block; +} + +QString BlockParameterPort::toVHDL(int context, int flags) { + QString expr=""; + QString ret=""; + ArithmeticEvaluator evaluator; + + if (!defaultValue.isNull()) { + expr = defaultValue.toString(); + try { + evaluator.setVariableMarkers("$"); + evaluator.setExpression(expr); + + double ifaceNb = 0.0; + double ifaceWidth = 0.0; + FunctionalInterface* iface = (FunctionalInterface*)(owner->getIfaceFromName(ifaceName)); + if (iface == NULL) return "INVALID_INTERFACE_NAME"; + + // must get the number of instance of + ifaceNb = iface->getInterfaceMultiplicity(); + + int result = 0; + evaluator.setVariableValue("$if_width",ifaceWidth); + evaluator.setVariableValue("$if_nb",ifaceNb); + result = (int)(evaluator.evaluate()); + ret.setNum(result); + } + catch(int e) { + cerr << "invalid expression in port parameter " << qPrintable(name) << " at character " << e << endl; + } + } + + return ret; +} + +void BlockParameterPort::setIfaceName(const QString& _ifaceName) { + ifaceName = _ifaceName; +} diff --git a/BlockParameterPort.h b/BlockParameterPort.h new file mode 100644 index 0000000..3050a1b --- /dev/null +++ b/BlockParameterPort.h @@ -0,0 +1,42 @@ +#ifndef __BLOCKPARAMETERPORT_H__ +#define __BLOCKPARAMETERPORT_H__ + +#include +#include + +#include + +#include "BlockParameter.h" +class BlockParameter; + +using namespace std; +using namespace Qt; + +class BlockParameterPort : public BlockParameter { + +public : + + BlockParameterPort(); + BlockParameterPort(AbstractBlock* _owner, const QString& _name, const QString& _value, const QString& _ifaceName); + + // getters + inline QString getIfaceName() { return ifaceName; } + inline QString getContext() { return "port";} + // setters + void setIfaceName(const QString& _ifaceName); + + // testers + bool isPortParameter(); + + // others + BlockParameter* clone(); + QString toVHDL(int context, int flags); + +private: + + QString ifaceName; + +}; + +#endif // __BLOCKPARAMETERPORT_H__ + diff --git a/BlockParameterUser.cpp b/BlockParameterUser.cpp new file mode 100644 index 0000000..d0d870f --- /dev/null +++ b/BlockParameterUser.cpp @@ -0,0 +1,56 @@ +#include "BlockParameterUser.h" + +BlockParameterUser::BlockParameterUser() : BlockParameter() { + userValue = defaultValue; +} + +BlockParameterUser::BlockParameterUser(AbstractBlock* _owner, const QString &_name, const QString &_value) : BlockParameter(_owner, _name, "string", _value) { + userValue = defaultValue; +} + +QVariant BlockParameterUser::getValue() { + if (isValueSet()) { + return userValue; + } + return defaultValue; +} + +bool BlockParameterUser::isUserParameter() { + return true; +} + +bool BlockParameterUser::isValueSet() { + if (userValue.isNull()) return false; + return true; +} + +bool BlockParameterUser::isDefaultValue() { + if (userValue == defaultValue) return true; + return false; +} + +BlockParameter* BlockParameterUser::clone() { + BlockParameter* block = new BlockParameterUser(owner,name,defaultValue.toString()); + return block; +} + +QString BlockParameterUser::toVHDL(int context, int flags) { + + // NB : context and flags are purely ignored + QString ret=""; + if (!userValue.isNull()) { + ret = userValue.toString(); + } + if (!defaultValue.isNull()) { + ret = defaultValue.toString(); + } + else { + ret = ""; + } + return ret; +} + +void BlockParameterUser::setValue(const QString& _value) { + userValue = QVariant(_value); +} + diff --git a/BlockParameterUser.h b/BlockParameterUser.h new file mode 100644 index 0000000..3da12a3 --- /dev/null +++ b/BlockParameterUser.h @@ -0,0 +1,57 @@ +#ifndef __BLOCKPARAMETERUSER_H__ +#define __BLOCKPARAMETERUSER_H__ + +#include +#include + +#include + +#include "BlockParameter.h" +class BlockParameter; + +using namespace std; +using namespace Qt; + +/* NOTES : + + A BlockParameterUser represents string that will be put in the generated VHDL code + each time a @val{param_name} is encountered. The default value of the string is given + at construction. If it is empty, user will have to provide a value before VHDL generation. + If it's not empty, user can still change this value before generation. + Since this string can be almost everything, it may lead to incorrect VHDL code. + But no validity check is done ! + + The type of such a parameter is always "string". + + */ +class BlockParameterUser : public BlockParameter { + +public : + + BlockParameterUser(); + BlockParameterUser(AbstractBlock* _owner, const QString& _name, const QString& _value); + + // getters + QVariant getValue(); + inline QString getContext() { return "user";} + // setters + void setValue(const QString& _value); + inline void resetToDefaultValue() { userValue = defaultValue; } + + // testers + bool isValueSet(); + bool isDefaultValue(); + bool isUserParameter(); + + // others + BlockParameter* clone(); + QString toVHDL(int context, int flags); + +private: + + QVariant userValue; + +}; + +#endif // __BLOCKPARAMETERUSER_H__ + diff --git a/BlockParameterWishbone.cpp b/BlockParameterWishbone.cpp new file mode 100644 index 0000000..4d13338 --- /dev/null +++ b/BlockParameterWishbone.cpp @@ -0,0 +1,90 @@ +#include "BlockParameterWishbone.h" + +BlockParameterWishbone::BlockParameterWishbone() : BlockParameter() { + userValue = defaultValue; + width = "0"; + wbAccess = BlockParameter::Read; + wbValue = "0"; + wbDuration = BlockParameter::Permanent; +} + +BlockParameterWishbone::BlockParameterWishbone(AbstractBlock* _owner, const QString& _name , const QString& _type, const QString& _width, const QString& _value, int _wbAccess, QString _wbValue, int _wbDuration) : BlockParameter (_owner, _name, _type, _value) { + userValue = _value; + width = _width; + wbAccess = _wbAccess; + wbValue = _wbValue; + wbDuration = _wbDuration; +} + +QVariant BlockParameterWishbone::getValue() { + if (isValueSet()) { + return userValue; + } + return defaultValue; +} + +bool BlockParameterWishbone::isWishboneParameter() { + return true; +} + +void BlockParameterWishbone::setValue(const QString& _value) { + userValue = QVariant(_value); +} + +bool BlockParameterWishbone::isValueSet() { + if (userValue.isNull()) return false; + return true; +} + +bool BlockParameterWishbone::isDefaultValue() { + if (userValue == defaultValue) return true; + return false; +} + +BlockParameter* BlockParameterWishbone::clone() { + BlockParameter* block = new BlockParameterWishbone(owner,name,getTypeString(),width,defaultValue.toString(),wbAccess,wbValue,wbDuration); + return block; +} + +QString BlockParameterWishbone::toVHDL(int context, int flags) { + + QString ret=""; + bool ok; + if ((context == BlockParameter::Entity) || (context == BlockParameter::Component)) { + + QString formatBool = "%1 : %2 std_logic"; + QString formatVector = "%1 : %2 std_logic_vector(%3 downto %4)"; + if ((flags & BlockParameter::NoComma) == 0) { + formatBool.append(";"); + formatVector.append(";"); + } + QString orientation=""; + if (wbAccess == Read) { + orientation = "out"; + } + else { + orientation = "in"; + } + if (type == Boolean) { + ret = formatVector.arg(name).arg(orientation); + } + else if (type == Natural) { + int w = width.toInt(&ok); + if (!ok) { + ret = formatVector.arg(name).arg(orientation).arg("INVALID SIZE").arg("0"); + } + else { + w -= 1; + ret = formatVector.arg(name).arg(orientation).arg(w).arg("0"); + } + } + else if (type == Expression) { + QString w = width.remove('$'); + w.append("-1"); + ret = formatVector.arg(name).arg(orientation).arg(w).arg("0"); + } + } + return ret; +} + + diff --git a/BlockParameterWishbone.h b/BlockParameterWishbone.h new file mode 100644 index 0000000..37be6c0 --- /dev/null +++ b/BlockParameterWishbone.h @@ -0,0 +1,58 @@ +#ifndef __BLOCKPARAMETERWISHBONE_H__ +#define __BLOCKPARAMETERWISHBONE_H__ + +#include +#include + +#include + +#include "BlockParameter.h" +class BlockParameter; + +using namespace std; +using namespace Qt; + +class BlockParameterWishbone : public BlockParameter { + +public : + + BlockParameterWishbone(); + BlockParameterWishbone(AbstractBlock* _owner, const QString& _name , const QString& _type, const QString& _width, const QString& _value, int _wbAccess = BlockParameter::Read, QString _wbValue = QString(), int _wbDuration = BlockParameter::Permanent); + + // getters + QVariant getValue(); + inline QString getContext() { return "wb";} + inline QString getWidth() { return width; } + inline int getWBAccess() { return wbAccess; } + inline QString getWBValue() { return wbValue; } + inline int getWBDuration() { return wbDuration; } + + // setters + void setValue(const QString& _value); + inline void resetToDefaultValue() { userValue = defaultValue; } + inline void setWBAccess(int _wbAccess) { wbAccess = _wbAccess; } + inline void setWBValue(QString _wbValue) { wbValue = _wbValue; } + inline void setWBDuration(int _wbDuration) { wbDuration = _wbDuration; } + + // testers + bool isValueSet(); + bool isDefaultValue(); + bool isWishboneParameter(); + + // others + BlockParameter* clone(); + QString toVHDL(int context, int flags); + +private: + + QString width; + QVariant userValue; + int wbAccess; + QString wbValue; + int wbDuration; + + +}; + +#endif // __BLOCKPARAMETERWISHBONE_H__ + diff --git a/BlockWidget.cpp b/BlockWidget.cpp new file mode 100644 index 0000000..3b8a658 --- /dev/null +++ b/BlockWidget.cpp @@ -0,0 +1,300 @@ +#include "BlockWidget.h" + +using namespace std; +using namespace Qt; + +BlockWidget::BlockWidget(QWidget *parent) : QWidget(parent) +{ + + rxComment = new QRegExp("(.*)--.*"); + rxComma = new QRegExp("(.*)[;]"); + rxPort = new QRegExp("[\\s\\t]*(.*)[\\s\\t]*:[\\s\\t]*(in|out|inout)[\\s\\t]*(.*)",CaseInsensitive,QRegExp::RegExp); + rxEnt = new QRegExp("[\\s\\t]*entity[\\s\\t]*(.*)[\\s\\t]*is",CaseInsensitive,QRegExp::RegExp); + rxArch = new QRegExp("[\\s\\t]*architecture[\\s\\t]*(.*)[\\s\\t]*of (.*)[\\s\\t]*is",CaseInsensitive,QRegExp::RegExp); + rxComp = new QRegExp("[\\s\\t]*component[\\s\\t]*(.*)[\\s\\t]*",CaseInsensitive,QRegExp::RegExp); + rxEnd = new QRegExp("[\\s\\t]*end(.*)",CaseInsensitive,QRegExp::RegExp); + rxComp = new QRegExp("[\\s\\t]*end component;",CaseInsensitive,QRegExp::RegExp); + rxGeneric = new QRegExp("[\\s\\t]*generic[\\s\\t]*[(][\\s\\t]*",CaseInsensitive,QRegExp::RegExp); + rxEndGen = new QRegExp("[\\s\\t]*[)]",CaseInsensitive,QRegExp::RegExp); + rxGen = new QRegExp("[\\s\\t]*(.*)[\\s\\t]*:[\\s\\t]*(.*)[\\s\\t]*:=[\\s\\t]*(.*)",CaseInsensitive,QRegExp::RegExp); + rxConst = new QRegExp("[\\s\\t]*constant[\\s\\t]*(.*)[\\s\\t]*:[\\s\\t]*(.)*[\\s\\t]*:=[\\s\\t]*(.*)",CaseInsensitive,QRegExp::RegExp); + rxWidth = new QRegExp(".*[(](.*)(downto|to)(.*)[)]",CaseInsensitive,QRegExp::RegExp); + + loadBt = new QPushButton("load VHDL"); + genBt = new QPushButton("generate XML"); + QHBoxLayout *widgetLayout = new QHBoxLayout; + QVBoxLayout *left = new QVBoxLayout; + QVBoxLayout *right = new QVBoxLayout; + + scrollPort = new QScrollArea; + scrollPort->setWidgetResizable(true); + twPort = new QTableWidget(this); + scrollPort->setWidget(twPort); + scrollGen = new QScrollArea; + scrollGen->setWidgetResizable(true); + twGen = new QTableWidget(this); + scrollGen->setWidget(twGen); + teName = new QTextEdit; + teBrief = new QTextEdit; + teDesc = new QTextEdit; + lblName = new QLabel("Block name :"); + lblBrief = new QLabel("Enter a brief description : "); + lblDesc = new QLabel("Enter a detailled description : "); + lblPort = new QLabel("Ports :"); + lblGen = new QLabel("Generics :"); + + connect(loadBt, SIGNAL(clicked()),this, SLOT(loadCode())); + connect(genBt, SIGNAL(clicked()), this, SLOT(generateXml())); + + left->addWidget(loadBt); + left->addWidget(lblPort); + left->addWidget(scrollPort); + left->addWidget(lblGen); + left->addWidget(scrollGen); + + right->addWidget(lblName); + right->addWidget(teName); + right->addWidget(lblBrief); + right->addWidget(teBrief); + right->addWidget(lblDesc); + right->addWidget(teDesc); + right->addWidget(genBt); + + widgetLayout->addLayout(left); + widgetLayout->addLayout(right); + setLayout(widgetLayout); + show(); +} + +BlockWidget::~BlockWidget() +{ + +} + +// This function opens a VHDL file and get the informations about the entity : +// First the generics, then the signals. +// You can edit the descriptions in the right, one for the brief description, the other for the detailled. +void BlockWidget::loadCode() { + + QString line, portName, portType, portId, genName, genType, genValue; + QStringList *portNameList, *portTypeList, *portIdList, *genNameList, *genTypeList, *genValueList; + cpt = 0; + twPort->setColumnCount(3); + twPort->setRowCount(cpt); + twGen->setColumnCount(3); + twGen->setRowCount(cpt); + portNameList = new QStringList; + portTypeList = new QStringList; + portIdList = new QStringList; + genNameList = new QStringList; + genTypeList = new QStringList; + genValueList = new QStringList; + + fileName = QFileDialog::getOpenFileName(this, + tr("Open File"), "C:", tr("Files (*.txt *.vhd)")); + QFile file(fileName); + + if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + QTextStream ts(&file); + while (!ts.atEnd()) + { + line = ts.readLine(); + if(rxComment->indexIn(line) != -1) { + line = rxComment->cap(1); + } + + if(rxEnt->indexIn(line)!= -1) { + + entName = rxEnt->cap(1); + teName->setText(entName); + QSize size = teName->document()->size().toSize(); + teName->setMaximumSize(size); + + while(rxEnd->indexIn(line) == -1) { + line = ts.readLine(); + if(rxComment->indexIn(line) != -1) { + line = rxComment->cap(1); + } + if(rxComma->indexIn(line) != -1) { + line = rxComma->cap(1); + } + if(rxGeneric->indexIn(line) != -1) { + while(rxEndGen->indexIn(line) == -1) { + line = ts.readLine(); + if(rxComment->indexIn(line) != -1) { + line = rxComment->cap(1); + } + if(rxComma->indexIn(line) != -1) { + line = rxComma->cap(1); + } + if(rxGen->indexIn(line) != -1) { + genName = rxGen->cap(1).simplified(); + genType = rxGen->cap(2).simplified(); + genValue = rxGen->cap(3).simplified(); + + genNameList->append(genName); + genTypeList->append(genType); + genValueList->append(genValue); + } + } + } + if(rxPort->indexIn(line) != -1) { + if(rxComment->indexIn(line) != -1) { + line = rxComment->cap(1); + } + if(rxComma->indexIn(line) != -1) { + line = rxComma->cap(1); + } + portName = rxPort->cap(1).simplified(); + portId = rxPort->cap(2).simplified(); + portType = rxPort->cap(3).simplified(); + portNameList->append(portName); + portIdList->append(portId); + portTypeList->append(portType); + } + } + } + } + + twGen->setRowCount(genNameList->size()); + for(int i = 0; i < genNameList->size(); i++) { + twGen->setItem(i, 0, new QTableWidgetItem(genNameList->at(i))); + twGen->setItem(i, 1, new QTableWidgetItem(genTypeList->at(i))); + twGen->setItem(i, 2, new QTableWidgetItem(genValueList->at(i))); + } + twPort->setRowCount(portNameList->size()); + for(int i = 0; i < portNameList->size(); i++) { + twPort->setItem(i, 0, new QTableWidgetItem(portIdList->at(i))); + twPort->setItem(i, 1, new QTableWidgetItem(portNameList->at(i))); + twPort->setItem(i, 2, new QTableWidgetItem(portTypeList->at(i))); + } + + file.close(); + scrollPort->setWidget(twPort); + return; +} + +// This function gets the informations in the table and the descriptions, and creates a XML file with this content +void BlockWidget::generateXml() { + + QString portName, portType, portId, genName, genType, genValue; + QStringList *portNameList, *portTypeList, *portIdList, *genNameList, *genTypeList, *genValueList; + int x, y, width; + brief = teBrief->toPlainText(); + desc = teDesc->toPlainText(); + entName = teName->toPlainText(); + + portNameList = new QStringList; + portTypeList = new QStringList; + portIdList = new QStringList; + genNameList = new QStringList; + genTypeList = new QStringList; + genValueList = new QStringList; + for(int i = 0; i < twGen->rowCount(); i++) { + genNameList->append(twGen->item(i,0)->text()); + genTypeList->append(twGen->item(i,1)->text()); + genValueList->append(twGen->item(i,2)->text()); + } + + for(int i = 0; i < twPort->rowCount(); i++) { + portIdList->append(twPort->item(i,0)->text()); + portNameList->append(twPort->item(i,1)->text()); + portTypeList->append(twPort->item(i,2)->text()); + } + + QDomDocument doc (entName); + QDomElement block = doc.createElement("block"); + block.setAttribute("name",entName); + block.setAttribute("version", "0.1"); + doc.appendChild(block); + + QDomElement comments = doc.createElement("comments"); + QDomElement category = doc.createElement("caterory"); + category.setAttribute("ids",""); + comments.appendChild(category); + + QDomElement eBrief = doc.createElement("brief"); + if(!brief.isEmpty()) { + QDomText txtBrief = doc.createTextNode(brief); + eBrief.appendChild(txtBrief); + comments.appendChild(eBrief); + } + QDomElement eDesc = doc.createElement("description"); + if(!desc.isEmpty()) { + QDomText txtDesc = doc.createTextNode(desc); + eDesc.appendChild(txtDesc); + comments.appendChild(eDesc); + } + block.appendChild(comments); + + QDomElement parameters = doc.createElement("parameters"); + QDomElement interfaces = doc.createElement("interfaces"); + QDomElement inputs = doc.createElement("inputs"); + QDomElement outputs = doc.createElement("outputs"); + QDomElement bidirs = doc.createElement("bidirs"); + block.appendChild(parameters); + block.appendChild(interfaces); + interfaces.appendChild(inputs); + interfaces.appendChild(outputs); + interfaces.appendChild(bidirs); + + for(int i = 0; i < twGen->rowCount(); i++) { + genName = genNameList->at(i); + genType = genTypeList->at(i); + genValue = genValueList->at(i); + QDomElement parameter = doc.createElement("parameter"); + parameter.setAttribute("name",genName); + parameter.setAttribute("type",genType); + parameter.setAttribute("value",genValue); + parameter.setAttribute("context","generic"); + parameters.appendChild(parameter); + } + + for(int i = 0; i < portIdList->size(); i++) { + portId = portIdList->at(i); + portName = portNameList->at(i); + portType = portTypeList->at(i); + if(rxWidth->indexIn(portType) != -1) { + x = rxWidth->cap(1).toInt(); + y = rxWidth->cap(3).toInt(); + if(x < y) + width = y - x + 1; + else if(x > y) + width = x - y + 1; + else + width = 1; + } + + if(portId.compare("in", CaseInsensitive) == 0) { + QDomElement input = doc.createElement("input"); + input.setAttribute("name",portName); + input.setAttribute("width", width); + inputs.appendChild(input); + } + else if(portId.compare("out", CaseInsensitive) == 0) { + QDomElement output = doc.createElement("output"); + output.setAttribute("name",portName); + output.setAttribute("width", width); + outputs.appendChild(output); + } + else if(portId.compare("inout", CaseInsensitive) == 0) { + QDomElement bidir = doc.createElement("bidir"); + bidir.setAttribute("name",portName); + bidir.setAttribute("width", width); + bidirs.appendChild(bidir); + } + } + + fileName = QFileDialog::getOpenFileName(this, tr("Open File"), + "C:", tr("Files (*.xml)")); + QFile file(fileName); + if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream ts(&file); + doc.save(ts,QDomNode::EncodingFromTextStream); + file.close(); + + QLabel *popup = new QLabel("Votre fichier XML est rempli"); + popup->show(); +} diff --git a/BlockWidget.h b/BlockWidget.h new file mode 100644 index 0000000..9150928 --- /dev/null +++ b/BlockWidget.h @@ -0,0 +1,42 @@ +#ifndef ENTITYWIDGET_H +#define ENTITYWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + +#include "Parameters.h" +#include "BlockParameter.h" +#include "Graph.h" + +class BlockWidget : public QWidget +{ + Q_OBJECT +public: + explicit BlockWidget(QWidget *parent = 0); + ~BlockWidget(); + +private: + QPushButton *loadBt, *genBt; + int cptIn, cptOut, cptInout, cpt; + QRegExp *rxPort, *rxEnt, *rxArch, *rxComp, *rxComment, *rxComma, + *rxEndComp, *rxEnd, *rxGeneric, *rxEndGen, *rxGen, *rxConst, *rxWidth; + QString fileName, txt, s, entName, brief, desc; + QScrollArea *scrollPort, *scrollGen; + QWidget *wid; + QLabel *labelAppli, *lblBrief, *lblDesc, *lblName, *lblPort, *lblGen; + QTableWidget *twPort, *twGen; + QTextEdit *teBrief, *teDesc, *teName; + +signals: + +public slots: + void loadCode(); + void generateXml(); +}; + +#endif // ENTITYWIDGET_H diff --git a/BlocksToConfigureWidget.cpp b/BlocksToConfigureWidget.cpp new file mode 100644 index 0000000..f860e52 --- /dev/null +++ b/BlocksToConfigureWidget.cpp @@ -0,0 +1,77 @@ +#include "BlocksToConfigureWidget.h" +#include +#include "ParametersWindow.h" + + +BlocksToConfigureWidget::BlocksToConfigureWidget(QList blocksList, Parameters *_params, QWidget *parent) : + QWidget(parent) +{ + blocks = blocksList; + params = _params; + layout = new QGridLayout; + tree = new QTreeWidget(this); + configureButton = new QPushButton("configure", this); + configureButton->setEnabled(false); + + connect(tree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(clicked())); + connect(tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(doubleClicked())); + connect(configureButton, SIGNAL(clicked()), this, SLOT(configure())); + + updateNamesList(); + tree->setHeaderLabel("blocks to configure"); + layout->addWidget(tree); + layout->addWidget(configureButton); + + this->setLayout(layout); + this->setFixedSize(300,230); +} + +void BlocksToConfigureWidget::updateNamesList() +{ + tree->clear(); + QTreeWidgetItem *item = NULL; + foreach(AbstractBlock *block, blocks){ + item = new QTreeWidgetItem(tree->invisibleRootItem()); + item->setData(0, Qt::DisplayRole, block->getName()); + } + +} + +void BlocksToConfigureWidget::updateBlocksList() +{ + blocks = params->getBlocksToConfigure(); + updateNamesList(); +} + +void BlocksToConfigureWidget::closeEvent(QCloseEvent *event) +{ + //when parameters validation is over, + //we start connections validation. + params->connectionsValidation(); +} + +void BlocksToConfigureWidget::clicked() +{ + if(tree->selectedItems().length() > 0) + configureButton->setEnabled(true); + else + configureButton->setEnabled(false); +} + +void BlocksToConfigureWidget::doubleClicked() +{ + configure(); +} + +void BlocksToConfigureWidget::configure() +{ + if(tree->selectedItems().length() > 0){ + bool firstItem = true; // We take only the first selected item + for (int i=0; itopLevelItemCount(); i++){ + if(firstItem && tree->topLevelItem(i)->isSelected()){ + firstItem = false; + new ParametersWindow(blocks.at(i), params, this); + } + } + } +} diff --git a/BlocksToConfigureWidget.h b/BlocksToConfigureWidget.h new file mode 100644 index 0000000..52b31fc --- /dev/null +++ b/BlocksToConfigureWidget.h @@ -0,0 +1,39 @@ +#ifndef __BLOCKSTOCONFIGUREWIDGET_H__ +#define __BLOCKSTOCONFIGUREWIDGET_H__ + +#include + +#include +#include +#include "Parameters.h" +#include "AbstractBlock.h" +#include + +class BlocksToConfigureWidget : public QWidget +{ + Q_OBJECT +public: + BlocksToConfigureWidget(QList blocksList, Parameters *_params, QWidget *parent=0); + + void updateNamesList(); + void updateBlocksList(); + + inline QTreeWidget *getTree() { return tree; } + inline QList getBlocks() { return blocks; } + +private: + void closeEvent(QCloseEvent * event); + + QList blocks; + QTreeWidget *tree; + QGridLayout *layout; + QPushButton *configureButton; + Parameters *params; + +private slots: + void clicked(); + void doubleClicked(); + void configure(); +}; + +#endif // BLOCKSTOCONFIGUREWIDGET_H diff --git a/BoxItem.cpp b/BoxItem.cpp new file mode 100644 index 0000000..77e9533 --- /dev/null +++ b/BoxItem.cpp @@ -0,0 +1,681 @@ +#include "BoxItem.h" +#include "GroupScene.h" +#include "ConnectionItem.h" +#include "InterfaceItem.h" +#include "GroupItem.h" +#include "Parameters.h" +#include "Exception.h" +#include "Dispatcher.h" +#include "FunctionalBlock.h" +#include "FunctionalInterface.h" +#include "ReferenceInterface.h" +#include "ReferenceBlock.h" +#include "ParametersWindow.h" +#include "BlockParameter.h" + + +BoxItem::BoxItem(AbstractBlock *_refBlock, + Dispatcher *_dispatcher, + Parameters *_params, GroupItem *parent) throw(Exception) : AbstractBoxItem( _refBlock, _dispatcher, _params, parent) { + + /* NOTE : + _refBlock : mandatory a FunctionalBlock or a GroupBlock + */ + if (_refBlock->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + + childGroupItem = NULL; + //boxWidth = params->defaultBlockWidth; + //boxHeight = params->defaultBlockHeight; + currentBorder = NoBorder; + selected = false; + + setZValue(100); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); + + initInterfaces(); + updateGeometry(); + resetInterfacesPosition(); + QPointF initPos = QPointF(0.0,0.0) - originPoint; + setPos(initPos); + //cout << "total size of block: " << totalWidth << "," << totalHeight << endl; + //cout << "pos in group: " << x() << "," << y() << endl; +} + + +BoxItem::~BoxItem() { +} + +void BoxItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + QPen pen(Qt::black, 3); + if(selected) + pen.setColor(Qt::red); + + painter->setPen(pen); + painter->setBrush(Qt::yellow); + + painter->drawRect(0,0,boxWidth, boxHeight); + painter->drawText(0,0,boxWidth, boxHeight,Qt::AlignCenter | Qt::TextWordWrap,QString(refBlock->getName())); + foreach(InterfaceItem *inter, interfaces) { + inter->paint(painter); + } +} + +void BoxItem::moveTo(QPointF dest) { + setPos(dest); + currentPosition = dest; +} + +bool BoxItem::isBoxItem() { + return true; +} + +void BoxItem::updateMinimumSize() { + + int maxSouth = 0; + int maxNorth = 0; + int maxEast = 0; + int maxWest = 0; + int nbSouth = nbInterfacesByOrientation(Parameters::South); + int nbNorth = nbInterfacesByOrientation(Parameters::North); + int nbMaxSN = nbNorth; + if (nbSouth > nbNorth) nbMaxSN = nbSouth; + int nbEast = nbInterfacesByOrientation(Parameters::East); + int nbWest = nbInterfacesByOrientation(Parameters::West); + int nbMaxEW = nbEast; + if (nbWest > nbEast) { + nbMaxEW = nbWest; + } + + int ifaceWidth = 0; + int ifaceHeight = 0; + + foreach(InterfaceItem* iface, interfaces) { + ifaceWidth = iface->getNameWidth(); + ifaceHeight = iface->getNameHeight(); + if (iface->getOrientation() == Parameters::South) { + if (ifaceWidth > maxSouth) maxSouth = ifaceWidth; + } + else if (iface->getOrientation() == Parameters::North) { + if (ifaceWidth > maxNorth) maxNorth = ifaceWidth; + } + else if (iface->getOrientation() == Parameters::East) { + if (ifaceWidth > maxEast) maxEast = ifaceWidth; + } + else if (iface->getOrientation() == Parameters::West) { + if (ifaceWidth > maxWest) maxWest = ifaceWidth; + } + } + + /* NB: the width layout is the following + ifaceMargin | maxWest | nameMargin | name | nameMargin | maxEast | ifaceMargin + */ + minimumBoxWidth = maxWest+maxEast+nameWidth+2*(ifaceMargin+nameMargin); + // if the minimum is not sufficent taking into account N/S interfaces + if (minimumBoxWidth < (nbMaxSN*ifaceHeight+ifaceMargin*(nbMaxSN+1))) { + minimumBoxWidth = (nbMaxSN*ifaceHeight+ifaceMargin*(nbMaxSN+1)); + } + minimumBoxHeight = maxNorth+maxSouth+3*ifaceMargin; + if (minimumBoxHeight < (nbMaxEW*ifaceHeight+ifaceMargin*(nbMaxEW+1))) { + minimumBoxHeight = (nbMaxEW*ifaceHeight+ifaceMargin*(nbMaxEW+1)); + } +} + + +/* updateGeometry() : + + */ +bool BoxItem::updateGeometry(ChangeType type) { + + currentPosition = pos(); + //cout << "current pos of block: " << currentPosition.x() << "," << currentPosition.y() << endl; + QPointF oldOrigin = originPoint; + QSize oldSize(totalWidth,totalHeight); + + bool boxSizeChanged = false; + + if ((type == Resize) || (type == InterfaceMove)) { + updateMinimumSize(); + } + + if (type == Resize) { + prepareGeometryChange(); + updateInterfacesAndConnections(); + boxSizeChanged = true; + } + if (boxWidth < minimumBoxWidth) { + boxWidth = minimumBoxWidth; + boxSizeChanged = true; + } + if (boxHeight < minimumBoxHeight) { + boxHeight = minimumBoxHeight; + boxSizeChanged = true; + } + if (boxSizeChanged) { + updateInterfacesAndConnections(); + } + + double x = 0.0; + double y = 0.0; + totalWidth = boxWidth; + totalHeight = boxHeight; + + if(isInterfaces(Parameters::East)){ + totalWidth += params->arrowWidth+params->arrowLineLength; + } + if(isInterfaces(Parameters::West)){ + totalWidth += params->arrowWidth+params->arrowLineLength; + x -= params->arrowWidth+params->arrowLineLength; + } + if(isInterfaces(Parameters::South)){ + totalHeight += params->arrowWidth+params->arrowLineLength; + } + if(isInterfaces(Parameters::North)){ + totalHeight += params->arrowWidth+params->arrowLineLength; + y -= params->arrowWidth+params->arrowLineLength; + } + QSizeF newSize(totalWidth,totalHeight); + originPoint.setX(x); + originPoint.setY(y); + + if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) { + prepareGeometryChange(); + return true; + } + return false; +} + +void BoxItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + + if(params->editState == Parameters::EditBlockMove) { + QPointF absPos = currentPosition + originPoint; + int marginConn = 2*(params->arrowWidth+params->arrowLineLength); + int gapX = event->scenePos().x() - cursorPosition.x(); + int gapY = event->scenePos().y() - cursorPosition.y(); + + //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | "; + //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | "; + + if (absPos.x()+gapX < marginConn) { + gapX = marginConn-absPos.x(); + } + if (absPos.y()+gapY < marginConn) { + gapY = marginConn-absPos.y(); + } + //cout << "gap: " << gapX << "," << gapY << endl; + QPointF gap(gapX,gapY); + currentPosition = currentPosition+gap; + setPos(currentPosition); + // update all connections from/to this block + foreach(ConnectionItem *item, getScene()->getConnectionItems()){ + if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) { + item->setPathes(); + } + } + cursorPosition = event->scenePos(); + + // udpate the groupitem + (getScene()->getGroupItem())->updateShape(); + } + else if(params->editState == Parameters::EditBlockResize) { + + int gapX = event->scenePos().x() - cursorPosition.x(); + int gapY = event->scenePos().y() - cursorPosition.y(); + //cout << "gap: " << gapX << "," << gapY << endl; + switch(currentBorder){ + case BorderEast: { + if(boxWidth+gapX > minimumBoxWidth){ + boxWidth += gapX; + } + break; + } + case BorderSouth: { + if(boxHeight+gapY > minimumBoxHeight){ + boxHeight += gapY; + } + break; + } + case CornerSouthEast: { + if(boxWidth+gapX > minimumBoxWidth){ + boxWidth += gapX; + } + if(boxHeight+gapY > minimumBoxHeight){ + boxHeight += gapY; + } + break; + } + case NoBorder: + cout << "abnormal case while resizing block" << endl; + break; + } + // recompute the geometry of the block and possibly the group item + if (updateGeometry()) { + (getScene()->getGroupItem())->updateShape(); + } + + cursorPosition = event->scenePos(); + } + else if(params->editState == Parameters::EditInterfaceMove) { + prepareGeometryChange(); + deplaceInterface(event->pos()); + // recompute the geometry of the block + if (updateGeometry()) { + cout << "must recompute group item geometry" << endl; + (getScene()->getGroupItem())->updateShape(); + } + // update connection from/to the selected interface + foreach(ConnectionItem *item, getScene()->getConnectionItems()){ + if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) { + item->setPathes(); + } + } + } +} + +void BoxItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + + QPointF pos = event->pos(); + qreal x = pos.x(); + qreal y = pos.y(); + + //QGraphicsItem::mousePressEvent(event); + + if(event->button() == Qt::RightButton) return; + + int mode = getScene()->getEditionMode(); + + dispatcher->setCurrentGroupWidget(getScene()->getGroupWindow()); + + if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) { + InterfaceItem *inter = getInterfaceFromCursor(x,y); + if (inter != NULL) { + + if (params->editState == Parameters::EditNoOperation) { + getScene()->setSelectedInterface(1,inter); + params->setEditState(Parameters::EditStartConnection); + } + else if (params->editState == Parameters::EditStartConnection) { + if (inter == getScene()->getSelectedInterface(1)) { + params->setEditState(Parameters::EditAbortConnection); + } + else { + getScene()->setSelectedInterface(2,inter); + params->setEditState(Parameters::EditCloseConnection); + } + } + } + } + else if (mode == GroupScene::ItemEdition) { + setZValue(zValue()+100); + if (params->cursorState == Parameters::CursorOnInterface) { + InterfaceItem *inter = getInterfaceFromCursor(x,y); + if (inter != NULL) { + if (inter == currentInterface) { + params->setEditState(Parameters::EditInterfaceDeselect); + } + else { + setFlag(ItemIsMovable, false); + currentInterface = inter; + params->setEditState(Parameters::EditInterfaceMove); + } + } + } + else if (params->cursorState == Parameters::CursorInBlock) { + selected = !selected; + params->setEditState(Parameters::EditBlockMove); + cursorPosition = event->scenePos(); + //cout << "cursor current pos. in scene " << cursorPosition.x() << "," << cursorPosition.y() << endl; + update(); + } + else if (params->cursorState == Parameters::CursorOnBorder) { + setFlag(ItemIsMovable, false); + cursorPosition = event->scenePos(); + params->setEditState(Parameters::EditBlockResize); + } + } +} + +void BoxItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + + setZValue(zValue()-100); + + int mode = getScene()->getEditionMode(); + + if (mode == GroupScene::AddConnection) { + + if (params->editState == Parameters::EditStartConnection) { + InterfaceItem* iface = getScene()->getSelectedInterface(1); + iface->selected = true; + update(iface->boundingRect()); + } + else if (params->editState == Parameters::EditAbortConnection) { + InterfaceItem* iface = getScene()->getSelectedInterface(1); + iface->selected = false; + update(iface->boundingRect()); + getScene()->setSelectedInterface(1,NULL); + params->setEditState(Parameters::EditNoOperation); + } + else if (params->editState == Parameters::EditCloseConnection) { + InterfaceItem* iface1 = getScene()->getSelectedInterface(1); + InterfaceItem* iface2 = getScene()->getSelectedInterface(2); + bool ok = dispatcher->connect(iface1,iface2); + if (ok) { + iface1->selected = false; + // no update needed since the whole scene will be repainted + getScene()->setSelectedInterface(1,NULL); + getScene()->setSelectedInterface(2,NULL); + params->setEditState(Parameters::EditNoOperation); + } + else { + getScene()->setSelectedInterface(2,NULL); + params->setEditState(Parameters::EditStartConnection); + } + } + } + else if (mode == GroupScene::ItemEdition) { + currentInterface = NULL; + params->editState = Parameters::EditNoOperation; + setFlag(ItemIsMovable); + } + + QGraphicsItem::mouseReleaseEvent(event); +} + +void BoxItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event) { + + QPointF pos = event->pos(); + qreal x = pos.x(); + qreal y = pos.y(); + currentBorder = NoBorder; + int mode = getScene()->getEditionMode(); + + if (mode == GroupScene::AddConnection) { + InterfaceItem* iface = getInterfaceFromCursor(x,y); + if (iface != NULL) { + params->cursorState = Parameters::CursorOnInterface; + setCursor(Qt::PointingHandCursor); + } + else { + params->cursorState = Parameters::CursorNowhere; + setCursor(Qt::ArrowCursor); + } + } + else if (mode == GroupScene::ItemEdition) { + int marginE = 5; + int marginS = 5; + + InterfaceItem* iface = getInterfaceFromCursor(x,y); + if (iface != NULL) { + params->cursorState = Parameters::CursorOnInterface; + setCursor(Qt::PointingHandCursor); + } + else if ((x>boxWidth-marginE)&&(xcursorState = Parameters::CursorOnBorder; + + if ((y>boxHeight-2*marginS)&&(yboxHeight-marginS)&&(ycursorState = Parameters::CursorOnBorder; + + if ((x>boxWidth-2*marginE)&&(x0) && (x0) && (ycursorState = Parameters::CursorInBlock; + setCursor(Qt::OpenHandCursor); + } + else { + params->cursorState = Parameters::CursorNowhere; + setCursor(Qt::ArrowCursor); + } + } + } + QGraphicsItem::hoverMoveEvent(event); +} + + +void BoxItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) { + + QMenu menu; + QAction* removeAction = menu.addAction("Remove"); + QAction* duplicateAction = menu.addAction("Duplicate"); + QAction* renameAction = menu.addAction("Rename"); + QAction* connectToGroup = NULL; + QAction* disconnectFromGroup = NULL; + QAction* showProperties = NULL; + QAction* cloneInterface = NULL; + QAction* openWindow = NULL; + QAction* showRstClkInter = NULL; + QAction* showParameters = NULL; + + InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y()); + if( ifaceItem != NULL){ + showProperties = menu.addAction("Show properties"); + + ConnectedInterface* iface = ifaceItem->refInter; + if ((iface->getDirection() == AbstractInterface::Input) && (iface->getConnectedFrom() == NULL)) { + connectToGroup = menu.addAction("Connect to group input"); + } + else if ((iface->getDirection() == AbstractInterface::Output) && (!iface->isConnectedTo())) { + connectToGroup = menu.addAction("Connect to group output"); + } + else if ((iface->getConnectionFromParentGroup() != NULL) || (iface->getConnectionToParentGroup() != NULL)) { + disconnectFromGroup = menu.addAction("Disconnect from group"); + } + + if (iface->isFunctionalInterface()) { + FunctionalInterface* fi = AI_TO_FUN(ifaceItem->refInter); + ReferenceInterface* ri = (ReferenceInterface*)(fi->getReference()); + if(ri->getMultiplicity() == -1 || ri->getMultiplicity() > 1){ + cloneInterface = menu.addAction("Clone interface"); + } + } + } + if(refBlock->isGroupBlock()){ + openWindow = menu.addAction("Open/show group window"); + } else { + showRstClkInter = menu.addAction("Show reset/clock interfaces"); + showRstClkInter->setCheckable(true); + showRstClkInter->setChecked(rstClkVisible); + + showParameters = menu.addAction("Show parameters"); + } + + QAction* selectedAction = NULL; + selectedAction = menu.exec(event->screenPos()); + + if(selectedAction == NULL) return ; + + if (selectedAction == removeAction) { + dispatcher->removeBlock(this); + } + else if (selectedAction == duplicateAction) { + dispatcher->duplicateBlock(this); + } + else if(selectedAction == renameAction){ + if(ifaceItem != NULL) + dispatcher->rename(ifaceItem); + else + dispatcher->rename(this); + } + else if(selectedAction == showProperties){ + dispatcher->showProperties(ifaceItem); + } + else if (selectedAction == connectToGroup){ + dispatcher->connectInterToGroup(ifaceItem); + } + else if (selectedAction == disconnectFromGroup) { + dispatcher->disconnectInterFromGroup(ifaceItem); + } + else if (selectedAction == cloneInterface){ + dispatcher->duplicateInterface(ifaceItem); + } + else if (selectedAction == openWindow){ + dispatcher->showRaiseWindow(this); + } + else if(selectedAction == showRstClkInter){ + dispatcher->showRstClkInter(this); + } + else if(selectedAction == showParameters){ + new ParametersWindow(refBlock, params, NULL); + } +} + +void BoxItem::save(QXmlStreamWriter &writer) { + if (refBlock->isFunctionalBlock()) { + writer.writeStartElement("bi_functional"); + + writer.writeAttribute("id",QString::number(id)); + writer.writeAttribute("ref_xml", ((FunctionalBlock*)refBlock)->getReferenceXmlFile()); + writer.writeAttribute("ref_md5", ((FunctionalBlock*)refBlock)->getReferenceHashMd5()); + writer.writeAttribute("name",refBlock->getName()); + QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y())); + writer.writeAttribute("position",attrPos); + QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight())); + writer.writeAttribute("dimension",attrDim); + + writer.writeStartElement("bif_parameters"); + foreach(BlockParameter *param,refBlock->getParameters()){ + writer.writeStartElement("bif_parameter"); + + writer.writeAttribute("name",param->getName()); + writer.writeAttribute("value",param->getValue().toString()); + /* + writer.writeAttribute("context",param->getStrContext()); + writer.writeAttribute("type",param->getTypeString()); + */ + writer.writeEndElement(); // + } + writer.writeEndElement(); // + + writer.writeStartElement("bif_ifaces"); + writer.writeAttribute("count",QString::number(interfaces.length())); + foreach(InterfaceItem* inter, interfaces){ + writer.writeStartElement("bif_iface"); + + writer.writeAttribute("id",QString::number(inter->getId())); + writer.writeAttribute("name",inter->getName()); + writer.writeAttribute("ref_name",inter->refInter->getName()); + writer.writeAttribute("orientation",inter->getStrOrientation()); + writer.writeAttribute("position",QString::number(inter->getPositionRatio())); + + writer.writeEndElement(); // + } + writer.writeEndElement(); // + + writer.writeEndElement(); // + } + else { + writer.writeStartElement("bi_group"); + + writer.writeAttribute("id",QString::number(id)); + writer.writeAttribute("inside_group",QString::number(childGroupItem->getId())); + QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y())); + writer.writeAttribute("position",attrPos); + QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight())); + writer.writeAttribute("dimension",attrDim); + + writer.writeStartElement("big_ifaces"); + writer.writeAttribute("count",QString::number(interfaces.length())); + foreach(InterfaceItem* inter, interfaces){ + writer.writeStartElement("big_iface"); + + writer.writeAttribute("id",QString::number(inter->getId())); + writer.writeAttribute("ref_name",inter->refInter->getName()); + writer.writeAttribute("orientation",inter->getStrOrientation()); + writer.writeAttribute("position",QString::number(inter->getPositionRatio())); + + writer.writeEndElement(); // + } + + writer.writeEndElement(); // + writer.writeEndElement(); // + } +} + +QDataStream &operator <<(QDataStream &out, BoxItem &b) { + out.setVersion(QDataStream::Qt_4_8); + + QByteArray blockData; + QDataStream toWrite(&blockData, QIODevice::WriteOnly); + + QString refXml = ((FunctionalBlock*)b.refBlock)->getReferenceXmlFile(); + QByteArray xmlFile = QByteArray(refXml.toStdString().c_str()); + toWrite << xmlFile; + + toWrite << b.id; + toWrite << (int)b.x(); + toWrite << (int)b.y(); + toWrite << b.boxWidth; + toWrite << b.boxHeight; + toWrite << b.getInterfaces().length(); + + for(int i=0; igetId(); + toWrite << inter->getName(); + toWrite << inter->getPositionRatio(); + toWrite << inter->getOrientation(); + } + + out << blockData; + + return out; +} + +QDataStream &operator >>(QDataStream &in, BoxItem &b) +{ + + in.setVersion(QDataStream::Qt_4_8); + + int x,y,nbInter; + + in >> b.id; + in >> x; + in >> y; + + b.setX(x); + b.setY(y); + + in >> b.boxWidth; + in >> b.boxHeight; + in >> nbInter; + + cout << "nbInter:" << nbInter << endl; + for(int i=0; i> id; + in >> name; + in >> positionRatio; + in >> orientation; + + inter->setId(id); + inter->setName(name); + inter->setPositionRatio(positionRatio); + inter->setOrientation(orientation); + inter->updatePosition(); + + } + + return in; +} diff --git a/BoxItem.h b/BoxItem.h new file mode 100644 index 0000000..74eb36a --- /dev/null +++ b/BoxItem.h @@ -0,0 +1,83 @@ +#ifndef __BLOCKITEM_H__ +#define __BLOCKITEM_H__ + +#include + +#include +#include + + +#include "AbstractBoxItem.h" +class AbstractBoxItem; + +class GroupItem; +class Parameters; +class Dispacther; + +#include "Exception.h" + +using namespace std; +using namespace Qt; + +/* NOTE : + + A BoxItem may represent a functional block or a group block within a group item, itslef + within a scene. What says what it represents is refBlock, i.e. if refBlock->isFunctionalBlock() + or refBlock->isGroupBlock() returns true. + */ +class BoxItem : public AbstractBoxItem { + +public: + BoxItem(AbstractBlock *_refBlock, Dispatcher *_dispatcher, Parameters *_params, GroupItem* parent) throw(Exception); + ~BoxItem(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + // getters + inline GroupItem *getChildGroupItem() { return childGroupItem; } + + // setters + inline void setChildGroupItem(GroupItem* item) { childGroupItem = item; } + + // testers + bool isBoxItem(); + + // others + void moveTo(QPointF dest); + void save(QXmlStreamWriter& writer); + +protected: + + void updateMinimumSize(); // modify the minimum size + bool updateGeometry(ChangeType type); // modify the originPoint and the total dimension + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + void hoverMoveEvent( QGraphicsSceneHoverEvent *event); + +private: + + /* NOTE : + A BlockItem is always graphically within a GroupItem, inside the same scene. + + A BlockItem may also be the graphical view of a GroupBlock. In this case, there exists a child scene + containing a GroupItem. insideGroup atribute refers to this GroupItem and thus, may be NULL if the current + blockItem represents a functional block + */ + GroupItem *childGroupItem; + + + friend QDataStream &operator<<(QDataStream &out, BoxItem &b); + friend QDataStream &operator>>(QDataStream &in, BoxItem &b); + +signals: + void itemMustBeDeleted(QGraphicsItem*); + +}; + +QDataStream & operator <<(QDataStream &out, BoxItem &b); +QDataStream & operator >>(QDataStream &in, BoxItem &b); + +#endif // __BLOCKITEM_H__ diff --git a/ConnectedInterface.cpp b/ConnectedInterface.cpp new file mode 100644 index 0000000..fbfa785 --- /dev/null +++ b/ConnectedInterface.cpp @@ -0,0 +1,68 @@ +#include "ArithmeticEvaluator.h" +#include "ConnectedInterface.h" +#include "FunctionalBlock.h" +#include "GroupBlock.h" + + +ConnectedInterface::ConnectedInterface(AbstractBlock* _owner) : AbstractInterface(_owner) { + connectedFrom = NULL; +} + +ConnectedInterface::ConnectedInterface(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _width, int _direction, int _purpose, int _level) : AbstractInterface(_owner, _name, _type, _width, _direction, _purpose, _level) { + connectedFrom = NULL; +} + +void ConnectedInterface::removeConnectedTo(ConnectedInterface *iface) { + connectedTo.removeOne(iface); +} + +void ConnectedInterface::clearConnections() { + connectedFrom = NULL; + connectedTo.clear(); +} + +void ConnectedInterface::clearConnectedTo() { + connectedTo.clear(); +} + +bool ConnectedInterface::connectTo(ConnectedInterface *iface) { + + if (canConnectTo(iface)) { + connectedTo.append(iface); + return true; + } + + return false; +} + +bool ConnectedInterface::connectFrom(ConnectedInterface *iface) { + if (canConnectFrom(iface)) { + connectedFrom = iface; + return true; + } + return false; +} + +/* getConnectionToParentGroup() : + if an interface among connectedTo is an interface of the parent group + returns it. +*/ +ConnectedInterface* ConnectedInterface::getConnectionToParentGroup() { + foreach(ConnectedInterface *iface, connectedTo) { + if (owner->getParent() == iface->owner) { + return iface; + } + } + return NULL; +} + +/* getConnectionFromParentGroup() : + if connectedFrom is an interface of the parent group + returns it. +*/ +ConnectedInterface *ConnectedInterface::getConnectionFromParentGroup() { + if ((connectedFrom != NULL) && (owner->getParent() == connectedFrom->owner)) { + return connectedFrom; + } + return NULL; +} diff --git a/ConnectedInterface.h b/ConnectedInterface.h new file mode 100644 index 0000000..968a00a --- /dev/null +++ b/ConnectedInterface.h @@ -0,0 +1,58 @@ +#ifndef __CONNECTEDINTERFACE_H__ +#define __CONNECTEDINTERFACE_H__ + +#include + +#include +#include + +#include "AbstractInterface.h" +class ReferenceInterface; + +#include "Exception.h" + +using namespace std; +using namespace Qt; + + +class ConnectedInterface : public AbstractInterface { + +public : + + ConnectedInterface(AbstractBlock* _owner); + ConnectedInterface(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _width, int _direction, int _purpose, int _level); + // getters + inline QList getConnectedTo() { return connectedTo;} + inline ConnectedInterface* getConnectedFrom() { return connectedFrom;} + + // setters + + // testers + inline bool isConnectedTo(){return connectedTo.length() != 0;} + inline bool isConnectedFrom(){return connectedFrom != NULL;} + virtual bool canConnectTo(AbstractInterface* iface) = 0; + virtual bool canConnectFrom(AbstractInterface* iface) = 0; + + // others + bool connectTo(ConnectedInterface* iface); + bool connectFrom(ConnectedInterface* iface); + ConnectedInterface* getConnectionToParentGroup(); + ConnectedInterface* getConnectionFromParentGroup(); + + virtual AbstractInterface *clone() = 0; + + void removeConnectedTo(ConnectedInterface *inter); + + virtual void clearConnectedTo(); + inline void clearConnectedFrom() { connectedFrom = NULL; } + virtual void clearConnections(); + //virtual void connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception) = 0; + +protected: + QList connectedTo; + ConnectedInterface* connectedFrom; + +}; + + +#endif // __CONNECTEDINTERFACE_H__ diff --git a/ConnectionItem.cpp b/ConnectionItem.cpp new file mode 100644 index 0000000..dee71ba --- /dev/null +++ b/ConnectionItem.cpp @@ -0,0 +1,762 @@ +#include "ConnectionItem.h" + +#include "Dispatcher.h" +#include "Parameters.h" +#include "AbstractBoxItem.h" +#include "ConnectedInterface.h" +#include "InterfaceItem.h" +#include "AbstractBlock.h" + +//int ConnectionItem::counter = 0; + +ConnectionItem::ConnectionItem(InterfaceItem* _iface1, + InterfaceItem* _iface2, + Dispatcher* _dispatcher, + Parameters* _params, + QGraphicsItem *_parent) : QGraphicsItem(_parent) { + + + dispatcher = _dispatcher; + params = _params; + + ConnectedInterface* ref1 = _iface1->refInter; + ConnectedInterface* ref2 = _iface2->refInter; + /* ref. note in .h + case 1 : ref1 is group interface, and ref2 block interface of a block within the group + case 2 : the opposite of case 1 + case 3 : ref1 and ref2 are block interface of blocks that are both within the same parent group. + */ + if (ref1->getOwner() == ref2->getOwner()->getParent()) { + + if (ref1->getDirection() == AbstractInterface::Input) { + fromInterfaceItem = _iface1; + toInterfaceItem = _iface2; + } + else if (ref1->getDirection() == AbstractInterface::InOut) { + fromInterfaceItem = _iface1; + toInterfaceItem = _iface2; + } + else if (ref1->getDirection() == AbstractInterface::Output) { + toInterfaceItem = _iface1; + fromInterfaceItem = _iface2; + } + } + else if (ref1->getOwner()->getParent() == ref2->getOwner()) { + + if (ref1->getDirection() == AbstractInterface::Input) { + fromInterfaceItem = _iface2; + toInterfaceItem = _iface1; + } + else if (ref1->getDirection() == AbstractInterface::InOut) { + fromInterfaceItem = _iface2; + toInterfaceItem = _iface1; + } + else if (ref1->getDirection() == AbstractInterface::Output) { + toInterfaceItem = _iface2; + fromInterfaceItem = _iface1; + } + } + // NB : this case is in fact similar to the previous. Kept here for clarity + else if (ref1->getOwner()->getParent() == ref2->getOwner()->getParent()) { + + if (ref1->getDirection() == AbstractInterface::Input) { + fromInterfaceItem = _iface2; + toInterfaceItem = _iface1; + } + else if (ref1->getDirection() == AbstractInterface::InOut) { + fromInterfaceItem = _iface2; + toInterfaceItem = _iface1; + } + else if (ref1->getDirection() == AbstractInterface::Output) { + toInterfaceItem = _iface2; + fromInterfaceItem = _iface1; + } + } + // adding this to interface items + fromInterfaceItem->addConnectionItem(this); + toInterfaceItem->addConnectionItem(this); + + selected = false; + marginConn = params->arrowLineLength+params->arrowWidth; + + setFlag(ItemIsSelectable); + setAcceptHoverEvents(true); + setFlag(ItemSendsGeometryChanges); + setCursor(Qt::PointingHandCursor); + setZValue(0); + + setPathes(); +} + + +ConnectionItem::ConnectionItem(const ConnectionItem ©) { + pointFrom = copy.pointFrom; + pointTo = copy.pointTo; + interPoint1 = copy.interPoint1; + interPoint2 = copy.interPoint2; + interPoint3 = copy.interPoint3; + interPoint4 = copy.interPoint4; +} + +ConnectionItem::~ConnectionItem() { +} + +ConnectionItem::ConnectionItem() { +} + +QPainterPath ConnectionItem::shape() const { + return pathShape; +} + +QRectF ConnectionItem::boundingRect() const { + + QPointF start, end; + + if(pointFrom.x() < pointTo.x()){ + start.setX(pointFrom.x()-20); + end.setX(pointTo.x()+20); + } else { + start.setX(pointTo.x()-20); + end.setX(pointFrom.x()+20); + } + if(pointFrom.y() < pointTo.y()){ + start.setY(pointFrom.y()-20); + end.setY(pointTo.y()+20); + } else { + start.setY(pointTo.y()-20); + end.setY(pointFrom.y()+20); + } + return QRectF(start, end); +} + +void ConnectionItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) { + + painter->setPen(Qt::blue); + if(selected){ + painter->setPen(Qt::red); + } + + painter->drawPath(pathPaint); +} + +void ConnectionItem::addInterPoint(QPointF point) { + +} + +void ConnectionItem::setPathes() { + + prepareGeometryChange(); + + pointFrom = fromInterfaceItem->getEndPointInGroup(); + pointTo = toInterfaceItem->getEndPointInGroup(); + + int oriFrom, oriTo; + oriFrom = fromInterfaceItem->getOrientation(); + oriTo = toInterfaceItem->getOrientation(); + +/* NB: if src or dest is onwed by a GroupItem the orientation + must be changed as it is a block. + */ + if(fromInterfaceItem->owner->isGroupItem()){ + switch(fromInterfaceItem->getOrientation()){ + case Parameters::North : + oriFrom = Parameters::South; + break; + case Parameters::South : + oriFrom = Parameters::North; + break; + case Parameters::East : + oriFrom = Parameters::West; + break; + case Parameters::West : + oriFrom = Parameters::East; + break; + } + } + if(toInterfaceItem->owner->isGroupItem()){ + switch(toInterfaceItem->getOrientation()){ + case Parameters::North : + oriTo = Parameters::South; + break; + case Parameters::South : + oriTo = Parameters::North; + break; + case Parameters::East : + oriTo = Parameters::West; + break; + case Parameters::West : + oriTo = Parameters::East; + break; + } + } + double gap1 = 0.0; + double gap2 = 0.0; + + if(oriFrom == Parameters::South) { + + // FROM SOUTH TO SOUTH + if(oriTo == Parameters::South) { + computeElle(oriFrom); + } + // FROM SOUTH TO NORTH + else if(oriTo == Parameters::North) { + gap1 = pointTo.y() - pointFrom.y(); + if (gap1 > 2*marginConn) { + computeStaircase(oriFrom); + } + else { + computeEsse(oriFrom); + } + } + // FROM SOUTH TO EAST OR WEST + else if ((oriTo == Parameters::East) || (oriTo == Parameters::West)){ + + gap1 = pointTo.x() - pointFrom.x(); + if (oriTo == Parameters::West) gap1 = -gap1; + gap2 = pointTo.y() - pointFrom.y(); + + if (gap1 > 0.0) { + if (gap2 > 0.0) { + computeHookSmallEnd(oriFrom,oriTo); + } + else { + computeOpenRect(oriFrom,oriTo); + } + } + else { + if (gap2 >= 0.0) { + computeCorner(oriFrom); + } + else { + computeHookSmallStart(oriFrom,oriTo); + } + } + } + } + else if(oriFrom == Parameters::North) { + + // FROM NORTH TO SOUTH + if(oriTo == Parameters::South) { + gap1 = pointFrom.y() - pointTo.y(); + if (gap1 > 2*marginConn) { + computeStaircase(oriFrom); + } + else { + computeEsse(oriFrom); + } + } + // FROM NORTH TO NORTH + else if(oriTo == Parameters::North) { + computeElle(oriFrom); + } + // FROM NORTH TO EAST OR WEST + else if ((oriTo == Parameters::East) || (oriTo == Parameters::West)){ + + gap1 = pointTo.x() - pointFrom.x(); + if (oriTo == Parameters::West) gap1 = -gap1; + gap2 = pointFrom.y() - pointTo.y(); + + if (gap1 > 0.0) { + if (gap2 > 0.0) { + computeHookSmallEnd(oriFrom,oriTo); + } + else { + computeOpenRect(oriFrom,oriTo); + } + } + else { + if (gap2 >= 0.0) { + computeCorner(oriFrom); + } + else { + computeHookSmallStart(oriFrom,oriTo); + } + } + } + } + else if(oriFrom == Parameters::East) { + // FROM EAST TO NORTH OR SOUTH + if ((oriTo == Parameters::South) || (oriTo == Parameters::North)){ + + gap1 = pointFrom.x() - pointTo.x(); + gap2 = pointFrom.y() - pointTo.y(); + if (oriTo == Parameters::North) gap2 = -gap2; + + if (gap1 > 0.0) { + if (gap2 > 0.0) { + computeHookSmallStart(oriFrom,oriTo); + } + else { + computeOpenRect(oriFrom,oriTo); + } + } + else { + if (gap2 >= 0.0) { + computeCorner(oriFrom); + } + else { + computeHookSmallEnd(oriFrom,oriTo); + } + } + } + else if(oriTo == Parameters::East) { + computeElle(oriFrom); + } + else if (oriTo == Parameters::West) { + gap1 = pointTo.x() - pointFrom.x(); + if (gap1 > 2*marginConn) { + computeStaircase(oriFrom); + } + else { + computeEsse(oriFrom); + } + } + } + else if (oriFrom == Parameters::West) { + + // FROM WEST TO NORTH OR SOUTH + if ((oriTo == Parameters::South) || (oriTo == Parameters::North)){ + + gap1 = pointTo.x() - pointFrom.x(); + gap2 = pointFrom.y() - pointTo.y(); + if (oriTo == Parameters::North) gap2 = -gap2; + + if (gap1 > 0.0) { + if (gap2 > 0.0) { + computeHookSmallStart(oriFrom,oriTo); + } + else { + computeOpenRect(oriFrom,oriTo); + } + } + else { + if (gap2 >= 0.0) { + computeCorner(oriFrom); + } + else { + computeHookSmallEnd(oriFrom,oriTo); + } + } + } + else if(oriTo == Parameters::East) { + gap1 = pointFrom.x() - pointTo.x(); + if (gap1 > 2*marginConn) { + computeStaircase(oriFrom); + } + else { + computeEsse(oriFrom); + } + } + else if (oriTo == Parameters::West) { + computeElle(oriFrom); + } + } + + pps.setWidth(5); + pathShape = pps.createStroke(pathPaint); +} + + +void ConnectionItem::computeEsse(int orientationFrom) { + + //cout << "drawing an esse" << endl; + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + double gap = marginConn; + if ((orientationFrom == Parameters::North)||(orientationFrom == Parameters::West)) gap = -gap; + QPointF p(0.0,0.0); + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + // must draw a complete esse + p = QPointF(pointFrom.x()+gap,pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointFrom.x()+gap,(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()-gap,(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()-gap,pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + + // must draw a complete esse + p = QPointF(pointFrom.x(),pointFrom.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()-gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(), pointTo.y()-gap); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } +} + +void ConnectionItem::computeStaircase(int orientationFrom) { + + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + if (pointFrom.y() == pointTo.y()) { + //cout << "drawing straight line" << endl; + pathPaint.lineTo(pointTo); + } + else { + //cout << "drawing a staircase" << endl; + // sufficient place to draw a simple staircase + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + if (pointFrom.x() == pointTo.x()) { + //cout << "drawing straight line" << endl; + pathPaint.lineTo(pointTo); + } + else { + //cout << "drawing a staircase" << endl; + // sufficient place to draw a simple staircase + p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } + } +} + +/* drawCorner(): + + A Corner has the following shape : + | + |__ + +*/ +void ConnectionItem::computeCorner(int orientationFrom) { + + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + //cout << "drawing a corner" << endl; + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + p = QPointF(pointTo.x(),pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + p = QPointF(pointFrom.x(),pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } +} + +/* drawOpenRect(): + + A OpenRect has the following shape : + __ + | + |_| +*/ +void ConnectionItem::computeOpenRect(int orientationFrom, int orientationTo) { + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + double gap1 = marginConn; + double gap2 = marginConn; + //cout << "drawing an OpenRect" << endl; + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + if (orientationFrom == Parameters::West) { + gap1 = -gap1; + } + if (orientationTo == Parameters::North) { + gap2 = -gap2; + } + p = QPointF(pointFrom.x()+gap1,pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointFrom.x()+gap1,pointTo.y()+gap2); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),pointTo.y()+gap2); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + if (orientationFrom == Parameters::North) { + gap1 = -gap1; + } + if (orientationTo == Parameters::West) { + gap2 = -gap2; + } + p = QPointF(pointFrom.x(),pointFrom.y()+gap1); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()+gap2,pointFrom.y()+gap1); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()+gap2,pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } +} + +/* drawHookSmallEnd(): + + A Hook has the following shape : + _ + | + |_| + Its end has always a size of marginConn +*/ +void ConnectionItem::computeHookSmallEnd(int orientationFrom, int orientationTo) { + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + double gap = marginConn; + //cout << "drawing a Hook with small end" << endl; + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + + if (orientationTo == Parameters::North) gap = -gap; + + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),pointTo.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + + if (orientationTo == Parameters::West) gap = -gap; + + p = QPointF(pointFrom.x(),(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()+gap,(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x()+gap,pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } +} + +/* drawHookSmallStart(): + + A Hook has the following shape : + _ + | + |_| + Its start has always a size of marginConn +*/ +void ConnectionItem::computeHookSmallStart(int orientationFrom, int orientationTo) { + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + double gap = marginConn; + //cout << "drawing a Hook with small start" << endl; + + if ((orientationFrom == Parameters::East)||(orientationFrom == Parameters::West)) { + + if (orientationFrom == Parameters::West) gap = -gap; + + p = QPointF(pointFrom.x()+gap,pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointFrom.x()+gap,(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),(pointFrom.y()+pointTo.y())/2.0); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } + else if ((orientationFrom == Parameters::South)||(orientationFrom == Parameters::North)) { + + if (orientationFrom == Parameters::North) gap = -gap; + + p = QPointF(pointFrom.x(),pointFrom.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointFrom.y()+gap); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF((pointFrom.x()+pointTo.x())/2.0,pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + } +} + +/* drawElle(): + + An Elle has the following shape : + | + |_| + +*/ +void ConnectionItem::computeElle(int orientationFrom) { + + pathPaint = QPainterPath(pointFrom); + interPoints.clear(); + QPointF p(0.0,0.0); + double x; + double y; + switch(orientationFrom){ + case Parameters::North : + if(pointFrom.y() < pointTo.y()) { + y = pointFrom.y()-marginConn; + } + else { + y = pointTo.y()-marginConn; + } + p = QPointF(pointFrom.x(),y); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),y); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + break; + case Parameters::South : + if(pointFrom.y() > pointTo.y()) { + y = pointFrom.y()+marginConn; + } + else { + y = pointTo.y()+marginConn; + } + p = QPointF(pointFrom.x(),y); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(pointTo.x(),y); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + break; + case Parameters::West : + if(pointFrom.x() < pointTo.x()) { + x = pointFrom.x()-marginConn; + } + else { + x = pointTo.x()-marginConn; + } + p = QPointF(x, pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(x, pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + break; + case Parameters::East : + if(pointFrom.x() > pointTo.x()) { + x = pointFrom.x()+marginConn; + } + else { + x = pointTo.x()+marginConn; + } + p = QPointF(x, pointFrom.y()); + pathPaint.lineTo(p); + interPoints.append(p); + p = QPointF(x, pointTo.y()); + pathPaint.lineTo(p); + interPoints.append(p); + pathPaint.lineTo(pointTo); + break; + } +} + +void ConnectionItem::setSelected(bool selected) { + this->selected = selected; + if(selected){ + setZValue(50); + } else { + setZValue(0); + } +} + +void ConnectionItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QGraphicsItem::mousePressEvent(event); + setZValue(zValue()+100); + setSelected(!selected); + update(boundingRect()); +} + +void ConnectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + QGraphicsItem::mouseReleaseEvent(event); + setZValue(zValue()-100); +} + +void ConnectionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + QGraphicsItem::mouseMoveEvent(event); +} + +void ConnectionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * event) { + QMenu menu; + QAction* removeAction = menu.addAction("Remove"); + QAction * selectedAction= menu.exec(event->screenPos()); + + if(selectedAction == removeAction){ + dispatcher->removeConnection(this); + dispatcher->removeUselessGroupInterfaces(); + } +} + +void ConnectionItem::prepareChange() { + prepareGeometryChange(); +} + +QDataStream &operator <<(QDataStream &out, ConnectionItem &c) { + out.setVersion(QDataStream::Qt_4_8); + + QByteArray connData; + QDataStream toWrite(&connData, QIODevice::WriteOnly); + + toWrite << c.id; + toWrite << c.getFromInterfaceItem()->getId(); + toWrite << c.getToInterfaceItem()->getId(); + + out << connData; + + return out; +} + +QDataStream &operator >>(QDataStream &in, ConnectionItem &c) { + in.setVersion(QDataStream::Qt_4_8); + + return in; +} diff --git a/ConnectionItem.h b/ConnectionItem.h new file mode 100644 index 0000000..567a31d --- /dev/null +++ b/ConnectionItem.h @@ -0,0 +1,107 @@ +#ifndef __CONNECTIONITEM_H__ +#define __CONNECTIONITEM_H__ + +#include + +#include +#include +#include + +class Dispatcher; +class Parameters; +class InterfaceItem; + +using namespace std; +using namespace Qt; + +/* NOTES : + + A connection item represent a graphical link between two interface items. + Even if it links two in/out interfaces, it is always oriented. + The orientation depends on the type and direction of linked interfaces : + + If interfaces are owned by blocks (group or func) that are within the same + parent group, then src must be an output, and dest an input, or both are in/out + and src/dest may be interchanged. + + If one interface I1 is owend by a block, and the other I2 by the parent group of that block, + then they have the same direction. If this direction is input, then src = I2 and dest = I1, + if it is output, then src = I1, dest = I2, and if it is in/out, no order matters. + + In order to simplify other methods, the constructor of ConnectionItem + checks these cases in order to retrieve the good src and dest if they are + not provided in the good order. + + */ +class ConnectionItem : public QGraphicsItem { + +public: + + ConnectionItem(InterfaceItem* _iface1, + InterfaceItem* _iface2, + Dispatcher* _dispatcher, + Parameters* _params, + QGraphicsItem* _parent); + ConnectionItem (const ConnectionItem & copy); + ConnectionItem(); + ~ConnectionItem(); + + QRectF boundingRect() const; + QPainterPath shape() const; + + void prepareChange(); + + inline InterfaceItem* getToInterfaceItem(){ return toInterfaceItem; } + inline void setToInterfaceItem(InterfaceItem *iface){ toInterfaceItem = iface; } + inline InterfaceItem* getFromInterfaceItem(){ return fromInterfaceItem; } + inline void setFromInterfaceItem(InterfaceItem* iface){ fromInterfaceItem = iface; } + inline int getId(){ return id; } + inline void setId(int id){ this->id = id; } + inline bool isSelected() { return selected; } + void setSelected(bool selected); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + void setPathes(); + void addInterPoint(QPointF point); + + static int counter; + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + +private: + + QPointF pointFrom; + QPointF pointTo; + QList interPoints; + QPointF interPoint1; + QPointF interPoint2; + QPointF interPoint3; + QPointF interPoint4; + + QPainterPath pathPaint; + QPainterPath pathShape; + QPainterPathStroker pps; + Dispatcher* dispatcher; + Parameters* params; + InterfaceItem* fromInterfaceItem; + InterfaceItem* toInterfaceItem; + bool selected; + int id; + int marginConn; + void computeEsse(int orientationFrom); + void computeStaircase(int orientationFrom); + void computeHookSmallEnd(int orientationFrom, int orientationTo); + void computeHookSmallStart(int orientationFrom, int orientationTo); + void computeOpenRect(int orientationFrom, int orientationTo); + void computeElle(int orientationFrom); + void computeCorner(int orientationFrom); + + friend QDataStream &operator << (QDataStream &out, ConnectionItem &c); + friend QDataStream &operator >> (QDataStream &in, ConnectionItem &c); +}; + +#endif // diff --git a/Dispatcher.cpp b/Dispatcher.cpp new file mode 100644 index 0000000..a85b942 --- /dev/null +++ b/Dispatcher.cpp @@ -0,0 +1,832 @@ +#include "Dispatcher.h" +#include "Parameters.h" +#include "MainWindow.h" + +#include "Graph.h" +#include "ReferenceBlock.h" +#include "GroupBlock.h" +#include "FunctionalBlock.h" + +#include "ConnectedInterface.h" +#include "ReferenceInterface.h" +#include "GroupInterface.h" +#include "FunctionalInterface.h" + +#include "GroupWidget.h" +#include "GroupScene.h" +#include "GroupItem.h" +#include "BoxItem.h" +#include "InterfaceItem.h" +#include "ConnectionItem.h" + +#include "BlockLibraryWidget.h" +#include "BlockLibraryTree.h" + +#include "InterfacePropertiesWindow.h" + + +Dispatcher::Dispatcher(Parameters* _params, MainWindow* _window) { + params = _params; + mainWindow =_window; + params->setDispatcher(this); + currentGroup = NULL; + topGroup = NULL; +} + +GroupWidget *Dispatcher::loadProject(const QString& filename) { + + QDomElement root; + try { + root = params->openProjectFile(filename); + } + catch(Exception err) { + return NULL; + } + + // creating the top widget/scene + topGroup = new GroupWidget(NULL,this,params); + currentGroup = topGroup; + // getting the newly created scene + GroupScene *scene = topGroup->getScene(); + params->setTopScene(scene); + params->setCurrentScene(scene); + + try { + params->loadProject(root); + } + catch(Exception e){ + cerr << qPrintable(e.getDefaultMessage()) << endl; + cerr << "Aborting ..." << endl; + // TO DO : deleteting topGroup and all + return NULL; + } + + return topGroup; +} + +void Dispatcher::closeCurrentProject() { + + foreach(GroupWidget* win, groupList) { + win->deleteLater(); + } + params->destroyGraph(); +} + +bool Dispatcher::connect(InterfaceItem *iface1, InterfaceItem *iface2) { + + ConnectedInterface* ref1 = iface1->refInter; + ConnectedInterface* ref2 = iface2->refInter; + // connect both interface + + bool ok1 = false; + bool ok2 = false; + + if (ref1->canConnectTo(ref2)) { + ok1 = ref1->connectTo(ref2); + ok1 = ok1 & ref2->connectFrom(ref1); + } + if (ref2->canConnectTo(ref1)) { + ok2 = ref2->connectTo(ref1); + ok2 = ok2 & ref1->connectFrom(ref2); + } + if ((ok1 == true) || (ok2 == true)) { + + iface1->getOwner()->getScene()->createConnectionItem(iface1,iface2); + + unselectAllItems(); + params->unsaveModif = true; + return true; + } + return false; +} + +void Dispatcher::checkSelection(){ + InterfaceItem *iface1 = NULL; + InterfaceItem *iface2 = NULL; + + GroupScene *scene = params->getCurrentScene(); + QList list = scene->getGroupAndBlocks(); + foreach(AbstractBoxItem *block, list){ + InterfaceItem *tmp = block->getCurrentInterface(); + if (tmp != NULL) { + if (iface1 == NULL) { + iface1 = tmp; + } + else { + iface2 = tmp; + } + } + } + if(iface1 != NULL && iface2 != NULL){ + connect(iface1,iface2); + } +} + +void Dispatcher::unselectAllItems(int direction){ + + GroupScene *scene = params->getCurrentScene(); + + foreach(BoxItem* block, scene->getBlockItems()) { + block->setSelected(false); + block->setCurrentInterface(NULL); + } + scene->unselecteInterfaces(); + scene->update(); +} + +void Dispatcher::setCurrentGroupWidget(GroupWidget *win){ + win->setFocus(); + win->changeConnectionMode(-1); + currentGroup = win; + params->setCurrentScene(win->getScene()); +} + +void Dispatcher::changeConnectionMode(int mode){ + + /* + foreach(GroupWidget* win, groupList){ + + QToolButton* buttonNewConnection = win->getButtonNewConnection(); + + QPalette pal = buttonNewConnection->palette(); + + if(mode == -1){ + if(params->sceneMode != Parameters::EditOnConnection){ + params->sceneMode = Parameters::EditOnConnection; + pal.setColor(QPalette::Button, QColor(Qt::lightGray)); + } else { + params->sceneMode = Parameters::EditNoOperation; + pal.setColor(QPalette::Button, QColor("#edeceb")); + } + } + else if(mode == Parameters::EditOnConnection){ + params->sceneMode = Parameters::EditOnConnection; + pal.setColor(QPalette::Button, QColor(Qt::lightGray)); + } + else { + params->sceneMode = Parameters::EditNoOperation; + pal.setColor(QPalette::Button, QColor("#edeceb")); + } + unselectAllInterfaces(); + + buttonNewConnection->setAutoFillBackground(true); + buttonNewConnection->setPalette(pal); + buttonNewConnection->update(); + } + */ +} + +void Dispatcher::rename(AbstractBoxItem *item){ + + bool ok; + QString text = QInputDialog::getText(NULL, "Rename an element", + "New name:", QLineEdit::Normal, + item->getRefBlock()->getName(), &ok); + + if(ok){ + if(!text.isEmpty() && text.length() < 30){ + item->getRefBlock()->setName(text); + if(item->isGroupItem()){ + if (currentGroup->isTopGroup()) { + mainWindow->setWindowTitle("blast - "+text); + } + else { + currentGroup->setWindowTitle("blast - "+text); + } + } + } + else { + QMessageBox::warning(NULL,"Error in given name", + "the element name must be shorter than 30 characters and can't be empty!", + QMessageBox::Ok); + rename(item); + } + } +} + +void Dispatcher::rename(InterfaceItem *item){ + bool ok; + QString text = QInputDialog::getText(NULL, "Rename an interface", + "New name:", QLineEdit::Normal, + item->refInter->getName(), &ok); + + /* CAUTION: when renaming an interface item, there are two cases : + - it refers to a functional block interface (fbi): the fbi keeps its name + and the new name is given to item + - it refers to a group block interface (gbi) : both gbi and item store the new name + + */ + if(ok && !text.isEmpty() && text.length() < 30) { + if (item->refInter->getOwner()->isGroupBlock()) { + item->refInter->setName(text); + } + item->setName(text); + } + else { + QMessageBox::warning(NULL,"Error in given name", + "the interface name must be shorter than 30 characters and can't be empty!", + QMessageBox::Ok); + rename(item); + } +} + +void Dispatcher::duplicateBlock(BoxItem *item){ + + GroupScene *scene = params->getCurrentScene(); + AbstractBlock* block = item->getRefBlock(); + AbstractBlock *newBlock; + + // only duplicate functional blocks + if(block->isFunctionalBlock()) { + + // adding to the model + FunctionalBlock* funBlock = (FunctionalBlock*)block; + newBlock = params->duplicateFunctionalBlock(funBlock); + // adding to the view + scene->createBlockItem(newBlock); + + params->unsaveModif = true; + } +} + +void Dispatcher::duplicateInterface(InterfaceItem *item){ + AbstractInterface *refI = item->refInter; + if (! refI->isFunctionalInterface()) return; + + AbstractBlock *refB = refI->getOwner(); + if(! refB->isFunctionalBlock()) return; + + FunctionalInterface* iface = (FunctionalInterface*)refI; + AbstractInterface *otherRef = iface->clone(); + if (otherRef == NULL) { + QMessageBox::warning(NULL,"Error while cloning an interface","the interface cannot be cloned because its maximum multiplicity is reached", QMessageBox::Ok); + return; + } + + refB->addInterface(otherRef); + + InterfaceItem *otherIface = new InterfaceItem(item->getPosition(),item->getOrientation(),(ConnectedInterface*)otherRef,item->getOwner(),params); + item->getOwner()->addInterface(otherIface,true); +} + + +void Dispatcher::addBlock(int idCategory, int idBlock) { + + GroupScene *scene = params->getCurrentScene(); + FunctionalBlock* newOne = params->addFunctionalBlock(idCategory, idBlock); + scene->createBlockItem(newOne); +} + + +GroupWidget *Dispatcher::createTopScene(){ + + // creating the model part of the group + Graph* graph = params->createGraph(); + GroupBlock *refBlock = graph->getTopGroup(); + + // creating a fake and not connected interface + //AbstractInterface* iface = new GroupInterface(refBlock,"grp_iface",AbstractInterface::Input,AbstractInterface::Top); + + // creating the group widget + topGroup = new GroupWidget(NULL,this,params); + currentGroup = topGroup; + // getting the newly created scene + GroupScene *scene = topGroup->getScene(); + params->setTopScene(scene); + params->setCurrentScene(scene); + // creating the view part of the group + GroupItem *group = new GroupItem(NULL,refBlock,this,params); + + // adding the fake interface to the top group item + //InterfaceItem* item = new InterfaceItem(0.0 , Parameters::West, (ConnectedInterface*)iface, group, params); + //group->addInterface(item,true); + + scene->setGroupItem(group); + + return topGroup; +} + +GroupWidget *Dispatcher::createChildScene(GroupWidget* parentWidget, BoxItem *upperItemOfGroupItem) { + + GroupBlock* parentBlock = NULL; + if (upperItemOfGroupItem != NULL) { + parentBlock = AB_TO_GRP(upperItemOfGroupItem->getRefBlock()); + } + // creating the model part of the group + GroupBlock *groupBlock = new GroupBlock(parentBlock); + groupBlock->setName("no name"); + // creating the view part of the group + GroupItem *groupItem = new GroupItem(upperItemOfGroupItem,groupBlock,this,params); + // creating the group widget + GroupWidget* group = new GroupWidget(parentWidget, this, params); + // getting the newly created scene + GroupScene *scene = group->getScene(); + // affecting group item to the scene + scene->setGroupItem(groupItem); + + return group; +} + +void Dispatcher::showRaiseWindow(AbstractBoxItem *item) { + GroupWidget* win = item->getScene()->getGroupWindow(); + if (win->isTopGroup()) { + mainWindow->show(); + mainWindow->raise(); + } + else { + win->show(); + win->raise(); + } + currentGroup = win; + params->setCurrentScene(currentGroup->getScene()); +} + +void Dispatcher::showRstClkInter(AbstractBoxItem *item) { + + item->setRstClkVisible(!item->isRstClkVisible()); + item->resetInterfacesPosition(); + + item->getScene()->updateConnectionItemsShape(); +} + +void Dispatcher::addNewFullGroup() { + +#ifdef DEBUG_INCLFUN + + QList listBlocks = params->getCurrentScene()->getSelectedBlocks(); //selected blocks in the current scene + QList listAbstractBlocks; //abstract blocks in the group + QList connections = params->getCurrentScene()->getConnectionItems(); + + /* What must be done: + 1 - creating a new GroupBlock + 2 - moving the selected blocks from the current GroupBlock to the new GroupBlock + 3 - creating a BlockItem that references the new GroupBlock + 4 - creating a new GroupWidget + 5 - creating a new GroupItem added to the scene of the GroupWidget + + */ + + /* step 1 : creating new GroupBlock that will have as a parent the GroupBlock + associated to the GroupItem of the current scene + */ + GroupBlock* parentBlock = params->getCurrentScene()->getGroupItem()->getRefBlock(); + GroupBlock* newGroupBlock = new GroupBlock(parentBlock); + /* step 2: moving selected blocks */ + foreach(BlockItem* blockItem, listBlocks) { + parentBlock->removeBlock(blockItem->getRefBlock()); + newGroupBlock->addBlock(blockItem->getRefBlock()); + } + + GroupItem *parent = currentGroup->getScene()->getGroupItem(); + GroupBlock *groupBlock = new GroupBlock(((GroupBlock*)parent->getRefBlock()),params->currentWindow); + BlockItem *blockItem = new BlockItem(params->getCurrentScene()->getGroupItem(),groupBlock,this,params); + GroupItem *groupItem = new GroupItem(blockItem,groupBlock,this,params); + + //create the new window + GroupWidget* win = new GroupWidget(this,params); + win->getScene()->setGroupItem(groupItem); + win->getScene()->addItem(groupItem); + ((GroupBlock*)groupItem->getRefBlock())->setWindow(win); + params->addWindow(win); + win->show(); + + //add the new group + params->getCurrentScene()->addBlockItem(blockItem); + params->getCurrentScene()->addItem(blockItem); + ((GroupItem*)params->getCurrentScene()->getGroupItem())->addBlockItem(blockItem); + + //replace selected blocks in the group + foreach(AbstractBoxItem *block, listBlocks){ + ((GroupItem*)block->getParentItem())->removeBlockItem(block); + ((GroupBlock*)block->getParentItem()->getRefBlock())->removeBlock(block->getRefBlock()); + params->getCurrentScene()->removeItem(block); + params->getCurrentScene()->removeBlockItem(block); + + groupBlock->addBlock(block->getRefBlock()); + listAbstractBlocks.append(block->getRefBlock()); + + block->setUpperItem(groupItem); + groupItem->addBlockItem(block); + win->getScene()->addItem(block); + win->getScene()->addBlockItem(block); + } + + //replace connection between selected blocks in the group + foreach(ConnectionItem *conn, connections){ + if(listBlocks.contains(conn->getFromInterfaceItem()->getOwner())){ + if(listBlocks.contains(conn->getToInterfaceItem()->getOwner())){ + parent->removeConnection(conn); + params->getCurrentScene()->removeItem(conn); + + groupItem->addConnection(conn); + win->getScene()->addItem(conn); + } + } + } + + //create new interfaces and connections for the new group + foreach(AbstractBoxItem *block, listBlocks){ + foreach(InterfaceItem *inter, block->getInterfaces()){ + cout << "inter : " << inter->getName().toStdString() << endl; + if(inter->refInter->getConnectedFrom() != NULL && inter->refInter->getDirection() == AbstractInterface::Input){ + cout << "connected from non null" << endl; + if(!listAbstractBlocks.contains(inter->refInter->getConnectedFrom()->getOwner())){ + + AbstractInterface *iface = inter->refInter->clone(0); + iface->setName(iface->getName()+"_group"); + groupBlock->addInterface(iface); + + InterfaceItem *ifaceItem = new InterfaceItem(0,Parameters::East,iface,blockItem,params); + blockItem->addInterface(ifaceItem); + blockItem->resetInterfacesPosition(); + + InterfaceItem *ifaceGroupItem = new InterfaceItem(0,Parameters::West,iface,groupItem,params); + groupItem->addInterface(ifaceGroupItem); + groupItem->resetInterfacesPosition(); + foreach(ConnectionItem* conn, currentGroup->getScene()->getInterfaceConnections(inter)){ + if(conn->getToInterfaceItem() == inter){ + conn->setToInterfaceItem(ifaceItem); + ifaceItem->refInter->setConnectedFrom(NULL); + conn->getFromInterfaceItem()->refInter->clearConnectedTo(); + connect(ifaceItem,conn->getFromInterfaceItem()); + } + } + params->setCurrentWindow(win); + + inter->refInter->setConnectedFrom(NULL); + ifaceGroupItem->refInter->clearConnectedTo(); + connect(inter,ifaceGroupItem); + params->setCurrentWindow(mainWindow); + } + } + + if(!inter->refInter->getConnectedTo().isEmpty() && inter->refInter->getDirection() == AbstractInterface::Output){ + cout << "connected to non null" << endl; + foreach(AbstractInterface *iface, inter->refInter->getConnectedTo()){ + if(!listAbstractBlocks.contains(iface->getOwner())){ + + AbstractInterface *iface = inter->refInter->clone(0); + iface->setName(iface->getName()+"_group"); + groupBlock->addInterface(iface); + + InterfaceItem *ifaceItem = new InterfaceItem(0,Parameters::East,iface,blockItem,params); + blockItem->addInterface(ifaceItem); + blockItem->resetInterfacesPosition(); + + foreach(ConnectionItem* conn, currentGroup->getScene()->getInterfaceConnections(inter)){ + if(conn->getFromInterfaceItem() == inter){ + conn->setFromInterfaceItem(ifaceItem); + iface->addConnectedTo(conn->getToInterfaceItem()->refInter); + conn->getToInterfaceItem()->refInter->setConnectedFrom(iface); + } + } + + InterfaceItem *ifaceGroupItem = new InterfaceItem(0,Parameters::East,iface,groupItem,params); + groupItem->addInterface(ifaceGroupItem); + groupItem->resetInterfacesPosition(); + inter->refInter->clearConnectedTo(); + ifaceGroupItem->refInter->setConnectedFrom(NULL); + connect(ifaceGroupItem,inter); + } + } + } + } + } + + //update window + + parent->updateShape(); + currentGroup->getScene()->updateConnectionItemsShape(); + currentGroup = win; + groupItem->updateShape(); + win->getScene()->updateConnectionItemsShape(); + groupItem->update(groupItem->boundingRect()); + +#endif +} + +void Dispatcher::removeBlock(AbstractBoxItem *item) { + +#ifdef DEBUG_INCLFUN + + GroupScene *scene = params->getCurrentScene(); + AbstractBlock* block = item->getRefBlock(); + if (block->isReferenceBlock()) return; + + GroupBlock* group = (GroupBlock*)item->getParentItem()->getRefBlock(); + + removeConnections(item); + + //récupérer l'objet + group->removeBlock(block); + + //remove the associated window + if(block->isGroupBlock()){ + foreach(QWidget *window, params->windows){ + if(!window->inherits("MainWindow")){ + if(((GroupWidget*)window)->getScene()->getGroupItem()->getRefBlock() == block){ + params->removeWindow(window); + delete window; + } + } + } + } + + delete block; + + //supprimer l'item de la scène + cout << "dispatcher : remove item of scene " << params->currentWindow << endl; + ((GroupItem *)scene->getGroupItem())->removeBlockItem(item); + scene->removeItem(item); + scene->removeBlockItem(item); + delete item; + + ((GroupItem *)scene->getGroupItem())->updateShape(); + + params->updateToolbar(); + params->unsaveModif = true; + +#endif +} + +void Dispatcher::removeAllBlockConnections(AbstractBoxItem *block) { + + GroupScene* scene = block->getScene(); + // supprimer les connections associées au bloc + foreach (ConnectionItem *conn, scene->getConnectionItems()) { + if(conn->getToInterfaceItem()->owner == block || conn->getFromInterfaceItem()->owner == block){ + removeConnection(conn); + } + } + scene->getGroupItem()->updateInterfacesAndConnections(); +} + +void Dispatcher::removeConnection(ConnectionItem *conn) { + + GroupScene *scene = params->getCurrentScene(); + GroupItem* currentGroup = scene->getGroupItem(); + + conn->getFromInterfaceItem()->unconnectTo(conn->getToInterfaceItem()); + + scene->removeConnectionItem(conn); + delete conn; + + currentGroup->updateInterfacesAndConnections(); + params->unsaveModif = true; +} + +void Dispatcher::removeUselessGroupInterfaces() { + + GroupScene *scene = params->getCurrentScene(); + GroupItem* currentGroup = scene->getGroupItem(); + + foreach(InterfaceItem *inter, currentGroup->getInterfaces()) { + if(inter->refInter->getConnectedTo().length() == 0) { + // NB : remove from view also remove from model + currentGroup->removeInterface(inter); + } + } + scene->updateConnectionItemsShape(); +} + +void Dispatcher::showBlocksLibrary(){ + cout << "showing block library" << endl; + mainWindow->getLibrary()->show(); + mainWindow->getLibrary()->raise(); +} + +void Dispatcher::showProperties(InterfaceItem *inter) +{ + new InterfacePropertiesWindow(inter); +} + +/* connectInterToGroup() : + The only way for a block (functional of group) within a GroupItem to be connected + to the latter is to right-click on one of its interfaces and to choose "connect to group". + That action will create a new InterfaceItem on the GroupItem and a connectionItem between the + interfaces. +*/ +void Dispatcher::connectInterToGroup(InterfaceItem *item){ + + // getting the GroupBlock and GroupItem that are parent of the block that owns item + ConnectedInterface *refInter = item->refInter; + GroupBlock* parentBlock = AB_TO_GRP(refInter->getOwner()->getParent()); + GroupItem *parentItem = item->getOwner()->getScene()->getGroupItem(); + + // creating/adding the group interface in the graph model + GroupInterface *groupInter = new GroupInterface(parentBlock,refInter->getName()+"_group",refInter->getDirection(),refInter->getLevel()); + groupInter->setType(refInter->getType()); + groupInter->setWidth(refInter->getWidth()); + groupInter->setPurpose(refInter->getPurpose()); + parentItem->getRefBlock()->addInterface(groupInter); + + // connect both interface + bool ok = true; + if (refInter->getDirection() == AbstractInterface::Output) { + ok = refInter->connectTo(groupInter); + ok = ok & groupInter->connectFrom(refInter); + } + else if (refInter->getDirection() == AbstractInterface::Input) { + ok = groupInter->connectTo(refInter); + ok = ok & refInter->connectFrom(groupInter); + } + else if (refInter->getDirection() == AbstractInterface::InOut) { + ok = refInter->connectTo(groupInter); + ok = ok & groupInter->connectFrom(refInter); + ok = ok & groupInter->connectTo(refInter); + ok = ok & refInter->connectFrom(groupInter); + } + if (!ok) { + cerr << "abnormal case while connecting a block iface to its parent group" << endl; + } + // creating/adding the group interface in the current scene model, and connection item + InterfaceItem *groupIfaceItem = new InterfaceItem(0,item->getOrientation(),groupInter,parentItem,params); + parentItem->addInterface(groupIfaceItem,true); + + parentItem->getScene()->createConnectionItem(item, groupIfaceItem); + + // if groupItem is not topGroup, must also add a new interface to the parent BlockItem + BoxItem* parent2Item = parentItem->getParentItem(); + if(parent2Item != NULL){ + InterfaceItem *blockIfaceItem = new InterfaceItem(0,item->getOrientation(),groupInter,parent2Item,params); + parent2Item->addInterface(blockIfaceItem,true); + } + + + parentItem->getScene()->updateConnectionItemsShape(); + unselectAllItems(); + params->unsaveModif = true; + + +} + +void Dispatcher::disconnectInterFromGroup(InterfaceItem *item) { + static QString fctName = "Dispatcher::disconnectInterFromGroup()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + // getting the GroupBlock and GroupItem that are parent of the block that owns item + ConnectedInterface *refInter = item->refInter; + ConnectedInterface *groupInter = NULL; + GroupBlock* parentGroup = AB_TO_GRP(refInter->getOwner()->getParent()); + GroupItem *parentItem = item->getOwner()->getScene()->getGroupItem(); + + // removing the connection from graph +#ifdef DEBUG + cout << "removing connections from graph ..." ; +#endif + + if (refInter->getDirection() == AbstractInterface::Output) { + groupInter = refInter->getConnectionToParentGroup(); // must be a single connection to + refInter->clearConnectedTo(); + groupInter->clearConnectedFrom(); + } + else if (refInter->getDirection() == AbstractInterface::Input) { + groupInter = refInter->getConnectedFrom(); + refInter->clearConnectedFrom(); + groupInter->clearConnectedTo(); + } + else if (refInter->getDirection() == AbstractInterface::InOut) { + groupInter = refInter->getConnectionToParentGroup(); // must be a single connection to + refInter->clearConnectedTo(); + refInter->clearConnectedFrom(); + groupInter->clearConnectedTo(); + groupInter->clearConnectedFrom(); + } +#ifdef DEBUG + cout << "done." << endl ; +#endif + + if (groupInter == NULL) { + cerr << "abnormal case 1 while removing an interface item of a block, linked to a parent group" << endl; + } + +#ifdef DEBUG + cout << "getting group interface item, and connection item ..." ; +#endif + + + InterfaceItem* groupIfaceItem = parentItem->searchInterfaceByRef(groupInter); + if (groupIfaceItem == NULL) { + cerr << "abnormal case 2 while removing an interface item of a block, linked to a parent group" << endl; + } + ConnectionItem* conn = parentItem->getScene()->searchConnectionItem(item,groupIfaceItem); + if (conn == NULL) { + cerr << "abnormal case 3 while removing an interface item of a block, linked to a parent group" << endl; + } +#ifdef DEBUG + cout << "done." << endl ; +#endif + + // removing the interface group item from the group item, and the connection item +#ifdef DEBUG + cout << "removing group interface item, and connection item ..." ; +#endif + + item->removeConnectionItem(conn); + groupIfaceItem->removeConnectionItem(conn); + parentItem->removeInterface(groupIfaceItem); // CAUTION : this deletes the interface item. + parentItem->getScene()->removeConnectionItem(conn); +#ifdef DEBUG + cout << "done." << endl ; +#endif + + // removing the interface box item in the parent scene +#ifdef DEBUG + cout << "removing the inteeface item of box item in parent scene if needed ..." ; +#endif + + BoxItem* parent2Item = parentItem->getParentItem(); + if (parent2Item != NULL) { + InterfaceItem* group2IfaceItem = parent2Item->searchInterfaceByRef(groupInter); + parent2Item->removeInterface(group2IfaceItem); + } +#ifdef DEBUG + cout << "done." << endl ; +#endif + + // removing the interface group from the group +#ifdef DEBUG + cout << "removing group interface ..." ; +#endif + parentGroup->removeInterface(groupInter); +#ifdef DEBUG + cout << "done." << endl ; +#endif + +} + +void Dispatcher::removeGroupInterface(InterfaceItem *item) { + static QString fctName = "Dispatcher::removeGroupInterface()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + /* NB: there is a single connection between item and another one that is owned + by a BoxItem. Thus, we just have to find it and to call disconnectInterFromGroup(); + */ + ConnectionItem* conn = item->connections.at(0); + if (conn->getFromInterfaceItem() == item) { + disconnectInterFromGroup(conn->getToInterfaceItem()); + } + else { + disconnectInterFromGroup(conn->getFromInterfaceItem()); + } +} + +GroupScene* Dispatcher::searchSceneById(int id) { + foreach(GroupWidget *group, groupList){ + if(group->getScene()->getId() == id) + return group->getScene(); + } + cout << "search scene by id :" << id << " :: not found..." << endl; + return NULL; +} + +GroupItem *Dispatcher::searchGroupItemById(int id) { + foreach(GroupWidget *group, groupList) { + GroupScene* scene = group->getScene(); + if (scene->getGroupItem()->getId() == id) return scene->getGroupItem(); + } + cout << "search GroupItem by id :" << id << " :: not found..." << endl; + return NULL; +} + +BoxItem *Dispatcher::searchBlockItemById(int id) { + foreach(GroupWidget *group, groupList) { + + GroupScene* scene = group->getScene(); + foreach(BoxItem *item, scene->getBlockItems()){ + if(item->getId() == id){ + return item; + } + } + } + cout << "search BlockItem by id :" << id << " :: not found..." << endl; + return NULL; +} + +InterfaceItem* Dispatcher::searchInterfaceItemById(int id) { + + foreach(GroupWidget *group, groupList) { + + GroupScene* scene = group->getScene(); + + foreach(InterfaceItem *item, scene->getGroupItem()->getInterfaces()){ + if(item->getId() == id){ + return item; + } + } + foreach(BoxItem *block, scene->getBlockItems()){ + foreach(InterfaceItem *item, block->getInterfaces()){ + if(item->getId() == id){ + return item; + } + } + } + } + cout << "search interface by id :" << id << " :: not found..." << endl; + return NULL; +} + diff --git a/Dispatcher.h b/Dispatcher.h new file mode 100644 index 0000000..4475518 --- /dev/null +++ b/Dispatcher.h @@ -0,0 +1,89 @@ +#ifndef __DISPATCHER_H__ +#define __DISPATCHER_H__ + +#include + +#include +#include +#include + +class Graph; +class Parameters; +class MainWindow; +class GroupWidget; +class GroupScene; +class AbstractBoxItem; +class GroupItem; +class BoxItem; +class ConnectionItem; +class InterfaceItem; + + + +using namespace std; +using namespace Qt; + +class Dispatcher { + +public: + Dispatcher(Parameters* _params, + MainWindow* _window); + + GroupWidget* loadProject(const QString& filename); + + inline int getNumberOfScenes() { return groupList.length(); } + bool connect(InterfaceItem *iface1, InterfaceItem *iface2); + void checkSelection(); + void unselectAllItems(int direction=0); + void setCurrentGroupWidget(GroupWidget *win); + void changeConnectionMode(int mode = -1); + void rename(AbstractBoxItem* item); + void rename(InterfaceItem* item); + GroupWidget* createTopScene(); + GroupWidget* createChildScene(GroupWidget* parentWidget, BoxItem* upperItemOfGroupItem = NULL); + void showRaiseWindow(AbstractBoxItem *item); + void showRstClkInter(AbstractBoxItem *item); + void addNewFullGroup(); + + inline GroupWidget* getCurrentGroup() { return currentGroup; } + + bool isCurrentProject; + +public slots: + + GroupScene* searchSceneById(int id); + BoxItem* searchBlockItemById(int id); + GroupItem* searchGroupItemById(int id); + InterfaceItem* searchInterfaceItemById(int id); + + void removeBlock(AbstractBoxItem* item); + void duplicateBlock(BoxItem* item); + void duplicateInterface(InterfaceItem* item); + void addBlock(int idCategory, int idBlock); + ConnectionItem *addConnection(InterfaceItem *input, InterfaceItem *output); + void removeAllBlockConnections(AbstractBoxItem *block); + void removeConnection(ConnectionItem *conn); + void removeUselessGroupInterfaces(); + void showBlocksLibrary(); + void showProperties(InterfaceItem *inter); + void connectInterToGroup(InterfaceItem* item); + void disconnectInterFromGroup(InterfaceItem* item); + void removeGroupInterface(InterfaceItem* item); + + void addConnection(); + + void closeCurrentProject(); + +private: + + // the model + Parameters* params; + + // attributes that corresponds to the views + MainWindow* mainWindow; + QList groupList; + GroupWidget* currentGroup; + GroupWidget *topGroup; +}; + +#endif // __DISPATCHER_H__ diff --git a/Exception.cpp b/Exception.cpp new file mode 100644 index 0000000..c45c367 --- /dev/null +++ b/Exception.cpp @@ -0,0 +1,39 @@ +#include "Exception.h" + +Exception::Exception(int _id) { + id = _id; + message = getDefaultMessage(); +} + + +Exception::Exception(const Exception& other) { + id = other.id; + message = other.message; +} + +QString Exception::getDefaultMessage() { + QString ret=""; + switch(id) { + case CONFIGFILE_CORRUPTED : ret = tr("Blast configuration file is corrupted"); break; + case CONFIGFILE_NOACCESS : ret = tr("Blast configuration file cannot be read"); break; + case PROJECTFILE_CORRUPTED : ret = tr("Project file is corrupted"); break; + case PROJECTFILE_NOACCESS : ret = tr("Project file cannot be read"); break; + case BLOCKPATH_NOACCESS : ret = tr("Directory containing references cannot be accessed (no rights/existence)"); break; + case IMPLPATH_NOACCESS : ret = tr("Directory containing implementations cannot be accessed (no rights/existence)"); break; + case BLOCKFILE_CORRUPTED : ret = tr("Block file is corrupted"); break; + case BLOCKFILE_NOACCESS : ret = tr("Block file cannot be read"); break; + case IMPLFILE_CORRUPTED : ret = tr("Implementation file is corrupted"); break; + case IMPLFILE_NOACCESS : ret = tr("Implementation file cannot be read"); break; + case BLOCK_NULL : ret = tr("A parameter of type AbstractBlock* has been provided with NULL value."); break; + case BLOCK_INVALID_TYPE : ret = tr("A parameter of type AbstractBlock* is used with an incorrect instance type."); break; + case IFACE_NULL : ret = tr("A parameter of type AbstractInterface* has been provided with NULL value."); break; + case IFACE_INVALID_TYPE : ret = tr("A parameter of type AbstractInterface* is used with an incorrect instance type."); break; + case IFACE_MULTIPLICITY_REACHED : ret = tr("Impossible to create another instance of a GraphInterface: the maximum multiplicity is reached."); break; + case BLOCKITEM_NULL : ret = tr("A parameter of type AbstractBlockItem* has been provided with NULL value."); break; + case BLOCKITEM_INVALID_TYPE : ret = tr("A parameter of type AbstractBlockItem* is used with an incorrect instance type."); break; + case WIDTHS_NOT_EQUALS : ret = tr("Two interfaces are connected but don't have the same widths."); break; + case INVALID_VALUE : ret = tr("parameter value is not correct (e.g. not numeric, invalid other parameter name, ...)."); break; + } + + return ret; +} diff --git a/Exception.h b/Exception.h new file mode 100644 index 0000000..32b2e49 --- /dev/null +++ b/Exception.h @@ -0,0 +1,80 @@ +/*-==============================================================- + +file : Exception.h + +creation date : 08/04/2015 + +author : S. Domas (sdomas@iut-bm.univ-fcomte.fr) + +description : + +supp. infos : saved in UTF-8 [éè] + +-==============================================================-*/ +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +#include +#include + +#include + +// exceptions for file accesses +#define CONFIGFILE_NOACCESS 1 +#define CONFIGFILE_CORRUPTED 2 + +#define PROJECTFILE_NOACCESS 3 +#define PROJECTFILE_CORRUPTED 4 + +#define BLOCKPATH_NOACCESS 5 +#define IMPLPATH_NOACCESS 6 + +#define BLOCKFILE_NOACCESS 7 +#define BLOCKFILE_CORRUPTED 8 + +#define IMPLFILE_NOACCESS 9 +#define IMPLFILE_CORRUPTED 10 + +#define VHDLFILE_NOACCESS 11 + +// exceptions for block manipulations +#define BLOCK_NULL 100 +#define BLOCK_INVALID_TYPE 101 + +// exceptions for interfaces manipulations +#define IFACE_NULL 200 +#define IFACE_INVALID_TYPE 201 +#define IFACE_MULTIPLICITY_REACHED 202 + +// exceptions for block items manipulations +#define BLOCKITEM_NULL 300 +#define BLOCKITEM_INVALID_TYPE 301 + +// exceptions for width interfaces validation +#define WIDTHS_NOT_EQUALS 400 + +// exceptions for VHDL generation +#define INVALID_VALUE 500 + +using namespace std; +using namespace Qt; + +class Exception : public QObject { + +public: + + Exception(int _id); + Exception(const Exception& other); + + inline int getType() { return id; } + inline void setMessage(QString _message) { message = _message; } + inline QString getMessage() { return message; } + QString getDefaultMessage(); + +private: + int id; + QString message; + +}; + +#endif //__EXCEPTION_H__ diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp new file mode 100644 index 0000000..f547084 --- /dev/null +++ b/FunctionalBlock.cpp @@ -0,0 +1,78 @@ +#include "FunctionalBlock.h" +#include "ReferenceBlock.h" +#include "GroupBlock.h" +#include "AbstractInterface.h" +#include "FunctionalInterface.h" +#include "ReferenceInterface.h" +#include "BlockParameter.h" + + +FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference) throw(Exception) : AbstractBlock() { + //if (! _reference->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + //if (! _group->isGroupBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + reference = _reference; + parent = _parent; + name = reference->getName(); +} + + +void FunctionalBlock::parametersValidation(QList* checkedBlocks, QList *blocksToConfigure) { + /* + checkedBlocks->append(this); + + foreach(BlockParameter* param, params){ + if(param->isUserParameter() && !param->isValueSet()){ + if(!blocksToConfigure->contains(param->getOwner())){ + blocksToConfigure->append(param->getOwner()); + } + } + } + foreach(AbstractInterface *inter, outputs){ + foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){ + if(!checkedBlocks->contains(connectedInter->getOwner())){ + connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure); + } + } + } + */ +} + +bool FunctionalBlock::isFunctionalBlock() { + return true; +} + +void FunctionalBlock::populate() { + int i; + BlockParameter* p; + AbstractInterface* inter; + + QList lstParam = reference->getParameters(); + for(i=0;iclone(); + addParameter(p); + } + + QList lstInter = reference->getInterfaces(); + for(i=0;igetXmlFile(); +} + +QString FunctionalBlock::getReferenceHashMd5() +{ + return ((ReferenceBlock *)reference)->getHashMd5(); +} diff --git a/FunctionalBlock.h b/FunctionalBlock.h new file mode 100644 index 0000000..1360244 --- /dev/null +++ b/FunctionalBlock.h @@ -0,0 +1,49 @@ +#ifndef __FUNCTIONALBLOCK_H__ +#define __FUNCTIONALBLOCK_H__ + +#include + +#include + +#include "AbstractBlock.h" +class AbstractBlock; +class ReferenceBlock; +class GroupBlock; +#include "Exception.h" +class Exception; + + +using namespace std; +using namespace Qt; + +/* NOTES : + - NEVER forget to call populate() after creating an instance of GraphBlock. + */ + +class FunctionalBlock : public AbstractBlock { +public: + + FunctionalBlock(GroupBlock* _parent, ReferenceBlock* _reference) throw(Exception); + + // getters + inline ReferenceBlock* getReference() { return reference; } + + // setters + + // testers + bool isFunctionalBlock(); + + // others + + void populate(); // create parameters and interface from reference block + void parametersValidation(QList *checkedBlocks, QList* blocksToConfigure); + + QString getReferenceXmlFile(); + QString getReferenceHashMd5(); + +private: + ReferenceBlock* reference; + +}; + +#endif // __FUNCTIONALBLOCK_H__ diff --git a/FunctionalInterface.cpp b/FunctionalInterface.cpp new file mode 100644 index 0000000..cc9f765 --- /dev/null +++ b/FunctionalInterface.cpp @@ -0,0 +1,197 @@ +#include "ArithmeticEvaluator.h" +#include "FunctionalInterface.h" +#include "ReferenceInterface.h" +#include "GroupInterface.h" +#include "FunctionalBlock.h" +#include "GroupBlock.h" + + +FunctionalInterface::FunctionalInterface(AbstractBlock* _owner, ReferenceInterface *_reference) throw(Exception) : ConnectedInterface(_owner) { + + if (_owner == NULL) throw(Exception(BLOCK_NULL)); + if (_reference == NULL) throw(Exception(IFACE_NULL)); + + if (! _owner->isFunctionalBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + if (! _reference->isReferenceInterface()) throw(Exception(IFACE_INVALID_TYPE)); + + reference = _reference; + + name = reference->getName(); + width = reference->getWidth(); + direction = reference->getDirection(); + purpose = reference->getPurpose(); + level = reference->getLevel(); + connectedFrom = NULL; +} + +bool FunctionalInterface::isFunctionalInterface() { + return true; +} + +int FunctionalInterface::getInterfaceMultiplicity() { + + int i=0; + int ifaceCount = 0; + FunctionalInterface* iface = NULL; + + if (direction == AbstractInterface::Input) { + QList inputs = owner->getInputs(); + for(i=0;igetReference() == reference) { + ifaceCount += 1; + } + } + } + else if (direction == AbstractInterface::Output) { + QList outputs = owner->getOutputs(); + for(i=0;igetReference() == reference) { + ifaceCount += 1; + } + } + } + else if (direction == AbstractInterface::InOut) { + QList bidirs = owner->getBidirs(); + for(i=0;igetReference() == reference) { + ifaceCount += 1; + } + } + } + if (ifaceCount == 0) { + return -1; + } + else if ( reference->getMultiplicity() == -1) { + return ifaceCount+1; + } + else if ( reference->getMultiplicity() > ifaceCount) { + return ifaceCount+1; + } + return -1; +} + +AbstractInterface *FunctionalInterface::clone() { + int id = getInterfaceMultiplicity(); + if (id < 0) return NULL; + FunctionalInterface *inter = new FunctionalInterface(owner, reference); + inter->setWidth(width); + inter->setDirection(direction); + inter->setPurpose(purpose); + inter->setLevel(level); + inter->connectFrom(NULL); + inter->setName(reference->getName()+"_"+QString::number(id)); + return inter; +} + +bool FunctionalInterface::canConnectTo(AbstractInterface *iface) { + + /* NOTE : + necessary conditions : + - this is an output or in/out interface + - iface type must be functional or group interface + - iface->connectedFrom must be NULL + + valid cases: + 1 - iface is owned by a block (group or func) that is within the same group as the block that own this + 1.1 - this is output and iface is input + 1.2 - both are inout + 2 - iface is owned by the parent group of the block that owns this + 2.1 - this is an output, iface is an output of the group + 2.2 - both are inout + + */ + if (direction == Input) return false; + if (iface->isReferenceInterface()) return false; + if (iface->getConnectedFrom() != NULL) return false; + + if (getOwner()->getParent() == iface->getOwner()->getParent()) { + + if ((direction == Output) && (iface->getDirection() == Input)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + else if (getOwner()->getParent() == iface->getOwner()) { + if ((direction == Output) && (iface->getDirection() == Output)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + + return false; + +} + +bool FunctionalInterface::canConnectFrom(AbstractInterface *iface) { + + /* NOTE : + necessary conditions : + - this is an input or in/out interface + - iface type must be functional or group interface + - this connectedFrom must be NULL + + valid cases: + 1 - iface is owned by a block (group or func) that is within the same group as the block that own this + 1.1 - this is input and iface is output + 1.2 - both are inout + 2 - iface is owned by the parent group of the block that owns this + 2.1 - this is an input, iface is an input of the group + 2.2 - both are inout + */ + if (direction == Output) return false; + if (iface->isReferenceInterface()) return false; + if (connectedFrom != NULL) return false; + + if (getOwner()->getParent() == iface->getOwner()->getParent()) { + + if ((direction == Input) && (iface->getDirection() == Output)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + else if (getOwner()->getParent() == iface->getOwner()) { + if ((direction == Input) && (iface->getDirection() == Input)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + + return false; +} + + +void FunctionalInterface::connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception) { + + /* + //inputs interfaces + double widthInput, widthOutput; + if(getDirection() == AbstractInterface::Input){ + widthInput = getDoubleWidth(); + widthOutput = getConnectedFrom()->getDoubleWidth(); + if(widthInput != widthOutput){ + throw new Exception(WIDTHS_NOT_EQUALS); + } + foreach(AbstractInterface *inter, getOwner()->getOutputs()){ + if(inter->isConnectedTo()){ + if((!interfacetoValidate->contains(inter)) && (!validatedInterfaces->contains(inter))){ + interfacetoValidate->push(inter); + } + } + } + } + //outputs interfaces + else if(getDirection() == AbstractInterface::Output){ + widthOutput = getDoubleWidth(); + foreach(AbstractInterface *inter, getConnectedTo()){ + widthInput = inter->getDoubleWidth(); + if(widthInput != widthOutput){ + throw new Exception(WIDTHS_NOT_EQUALS); + } + } + foreach(AbstractInterface *inter, getConnectedTo()){ + if((!interfacetoValidate->contains(inter)) && (!validatedInterfaces->contains(inter))){ + interfacetoValidate->push(inter); + } + } + } + else if(getDirection() == AbstractInterface::InOut){ + + } + + */ +} diff --git a/FunctionalInterface.h b/FunctionalInterface.h new file mode 100644 index 0000000..1dfa726 --- /dev/null +++ b/FunctionalInterface.h @@ -0,0 +1,59 @@ +#ifndef __FUNCTIONALINTERFACE_H__ +#define __FUNCTIONALINTERFACE_H__ + +#include + +#include +#include + +#include "ConnectedInterface.h" +class ReferenceInterface; + +#include "Exception.h" + +using namespace std; +using namespace Qt; + + +/* NOTES : + + - A FunctionalInterface instance can be obtained by: + - cloning an existing ReferenceInterface when a new functionalBlock is created by cloning a ReferenceBlock + - cloning an existing FunctionalInterface when its reference has a multiplicity > 1 + + - For an Input, the list connectedFrom can contain ONLY ONE element + - For an Output, the list connectedTo can contain several element + - If connectedTo contains something, then connectedFrom is NULL + - If connectedFrom contains something, the connectedTo is empty. + */ + +class FunctionalInterface : public ConnectedInterface { + +public : + FunctionalInterface(); + FunctionalInterface(AbstractBlock* _owner, ReferenceInterface* _reference) throw(Exception); // create a default interface (see AbstractInterface) + + // getters + inline ReferenceInterface* getReference() { return reference; } + + // setters + + // testers + bool isFunctionalInterface(); + bool canConnectTo(AbstractInterface* iface); + bool canConnectFrom(AbstractInterface* iface); + + // others + + AbstractInterface* clone(); + + void connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception); + int getInterfaceMultiplicity(); + +private: + + ReferenceInterface* reference; + +}; + +#endif // __FUNCTIONALINTERFACE_H__ diff --git a/Graph.cpp b/Graph.cpp new file mode 100644 index 0000000..1c87123 --- /dev/null +++ b/Graph.cpp @@ -0,0 +1,31 @@ +#include "Graph.h" +#include "GroupBlock.h" +#include "ReferenceBlock.h" +#include "FunctionalBlock.h" + +Graph::Graph() { + topGroup = new GroupBlock(NULL); + topGroup->setName("top group"); +} + +Graph::~Graph() { + delete topGroup; +} + +QList Graph::getOutsideInterfaces() { + return topGroup->getInterfaces(); +} + +GroupBlock* Graph::createChildBlock(GroupBlock* parent) { + GroupBlock* b = new GroupBlock(parent); + return b; +} + +FunctionalBlock* Graph::addFunctionalBlock(GroupBlock* group, ReferenceBlock* ref) { + + FunctionalBlock* newBlock = new FunctionalBlock(group,ref); + newBlock->populate(); + group->addBlock(newBlock); + + return newBlock; +} diff --git a/Graph.h b/Graph.h new file mode 100644 index 0000000..7f34682 --- /dev/null +++ b/Graph.h @@ -0,0 +1,35 @@ +#ifndef __GRAPH_H__ +#define __GRAPH_H__ + +#include + +#include +#include + +class GroupBlock; +class ReferenceBlock; +class FunctionalBlock; +class AbstractInterface; + +using namespace std; +using namespace Qt; + + +class Graph { + +public: + Graph(); + ~Graph(); + + QList getOutsideInterfaces(); + inline GroupBlock* getTopGroup() { return topGroup; } + + GroupBlock* createChildBlock(GroupBlock* parent); + FunctionalBlock* addFunctionalBlock(GroupBlock *group, ReferenceBlock *ref); + +private: + GroupBlock* topGroup; + +}; + +#endif // __GRAPH_H__ diff --git a/GroupBlock.cpp b/GroupBlock.cpp new file mode 100644 index 0000000..4ec7f6b --- /dev/null +++ b/GroupBlock.cpp @@ -0,0 +1,78 @@ +#include "GroupBlock.h" +#include "BlockParameterGeneric.h" +#include "AbstractInterface.h" +#include "string.h" +#include + +int GroupBlock::counter = 1; + +GroupBlock::GroupBlock(GroupBlock *_parent) throw(Exception) : AbstractBlock() { + + // force topGroup to false if this group has a parent + if (_parent != NULL) { + topGroup = false; + name = QString("sub_group")+"_"+QString::number(counter++); + } + else { + topGroup = true; + name = QString("top_group"); + } + parent = _parent; + if (parent != NULL) { + // adding this to the child blocks of parent + AB_TO_GRP(parent)->addBlock(this); + } +} + +GroupBlock::~GroupBlock() { + foreach(AbstractBlock* block, blocks) { + delete block; + } +} + +bool GroupBlock::isGroupBlock() { + return true; +} + +void GroupBlock::setParent(AbstractBlock *_parent) { + parent = _parent; + if (parent != NULL) { + topGroup = false; + } +} + +void GroupBlock::removeBlock(AbstractBlock* block) { + blocks.removeAll(block); +} + +void GroupBlock::parametersValidation(QList *checkedBlocks, QList *blocksToConfigure) { + + /* + checkedBlocks->append(this); + + foreach(BlockParameter* param, params){ + if(param->isUserParameter() && !param->isValueSet()){ + if(!blocksToConfigure->contains(param->getOwner())){ + blocksToConfigure->append(param->getOwner()); + } + } + } + foreach(AbstractInterface *inter, outputs){ + foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){ + if(!checkedBlocks->contains(connectedInter->getOwner())){ + connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure); + } + } + } + */ +} + +void GroupBlock::addGenericParameter(QString name, QString type, QString value) { + BlockParameter* param = new BlockParameterGeneric(this, name, type, value); + params.append(param); +} + +void GroupBlock::removeGenericParameter(QString name) { + BlockParameter* p = getParameterFromName(name); + if (p != NULL) params.removeAll(p); +} diff --git a/GroupBlock.h b/GroupBlock.h new file mode 100644 index 0000000..3316637 --- /dev/null +++ b/GroupBlock.h @@ -0,0 +1,47 @@ +#ifndef __GROUPBLOCK_H__ +#define __GROUPBLOCK_H__ + +#include + +#include + +#include "AbstractBlock.h" +class AbstractBlock; +#include "Exception.h" +class Exception; + +using namespace std; +using namespace Qt; + + +class GroupBlock : public AbstractBlock { +public: + + GroupBlock(GroupBlock* _parent) throw(Exception); + virtual ~GroupBlock(); + + // getters + + // setters + void setParent(AbstractBlock *_parent); + + // testers + bool isGroupBlock(); + inline bool isTop() { return topGroup; } + + // others + inline void addBlock(AbstractBlock* block) { blocks.append(block); } + void removeBlock(AbstractBlock* block); + void parametersValidation(QList *checkedBlocks, QList* blocksToConfigure); + void addGenericParameter(QString name, QString type, QString value); + void removeGenericParameter(QString name); + // public attributes + static int counter; + +private: + bool topGroup; + QList blocks; // contains instances of FunctionalBlock or GroupBlock + +}; + +#endif // __GROUPBLOCK_H__ diff --git a/GroupInterface.cpp b/GroupInterface.cpp new file mode 100644 index 0000000..14f8b43 --- /dev/null +++ b/GroupInterface.cpp @@ -0,0 +1,116 @@ +#include "GroupInterface.h" +#include "FunctionalInterface.h" +#include "GroupBlock.h" + +GroupInterface::GroupInterface(AbstractBlock* _owner, const QString& _name, int _direction, int _level) throw(Exception) : ConnectedInterface(_owner,_name,"expression","",_direction,AbstractInterface::Data,_level) { + if (! _owner->isGroupBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + + /* If the owner group is the top group, then all its interfaces are at top level => force them to be top. + If not, force them to be basic + */ + if (((GroupBlock*)_owner)->isTop()) { + level = AbstractInterface::Top; + } + else { + level = AbstractInterface::Basic; + } + connectedFrom = NULL; +} + +bool GroupInterface::isGroupInterface() { + return true; +} + +AbstractInterface *GroupInterface::clone() { + GroupInterface *inter = new GroupInterface(owner,name,direction,level); + inter->setWidth(width); + inter->setDirection(direction); + inter->setPurpose(purpose); + inter->setLevel(level); + inter->connectFrom(NULL); + + return inter; +} + + +bool GroupInterface::canConnectTo(AbstractInterface *iface) { + + /* NOTE : + necessary conditions : + - iface type must be functional or group interface + - iface->connectedFrom must be NULL + + valid cases: + 1 - this is owned by the parent group of the block (group or func) that owns iface + 1.1 - this is input and iface is input + 1.2 - both are inout + 2 - this is owned by a group that has the same parent as the block (group or func) that owns iface + 2.1 - this is an output, iface is an input of the group + 2.2 - both are inout + 3 - this is owned by a group and iface by its parent group + 2.1 - this is an output, iface is an output of the group + 2.2 - both are inout + + + */ + if (iface->isReferenceInterface()) return false; + if (iface->getConnectedFrom() != NULL) return false; + + if (this->getOwner() == iface->getOwner()->getParent()) { + if ((direction == Input) && (iface->getDirection() == Input)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + + } + else if (this->getOwner()->getParent() == iface->getOwner()->getParent()) { + if ((direction == Output) && (iface->getDirection() == Input)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + else if (this->getOwner()->getParent() == iface->getOwner()) { + if ((direction == Output) && (iface->getDirection() == Output)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + + return false; +} + +bool GroupInterface::canConnectFrom(AbstractInterface *iface) { + + /* NOTE : + necessary conditions : + - iface type must be functional or group interface + - this->connectedFrom must be NULL + + valid cases: + 1 - this is owned by the parent group of the block (group or func) that owns iface + 1.1 - this is output and iface is output + 1.2 - both are inout + 2 - this is owned by a group that has the same parent as the block (group or func) that owns iface + 2.1 - this is an input, iface is an output of the group + 2.2 - both are inout + 3 - this is owned by a group and iface by its parent group + 2.1 - this is an input, iface is an input of the group + 2.2 - both are inout + */ + if (iface->isReferenceInterface()) return false; + if (getConnectedFrom() != NULL) return false; + + if (this->getOwner() == iface->getOwner()->getParent()) { + if ((direction == Output) && (iface->getDirection() == Output)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + + } + else if (this->getOwner()->getParent() == iface->getOwner()->getParent()) { + if ((direction == Input) && (iface->getDirection() == Output)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + else if (this->getOwner()->getParent() == iface->getOwner()) { + if ((direction == Input) && (iface->getDirection() == Input)) return true; + if ((direction == InOut) && (iface->getDirection() == InOut)) return true; + } + + return false; +} + +void GroupInterface::connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception) { + cout << "group interface connection validation" << endl; +} diff --git a/GroupInterface.h b/GroupInterface.h new file mode 100644 index 0000000..2a22dc7 --- /dev/null +++ b/GroupInterface.h @@ -0,0 +1,54 @@ +#ifndef __GROUPINTERFACE_H__ +#define __GROUPINTERFACE_H__ + +#include + +#include +#include + +#include "ConnectedInterface.h" +#include "Exception.h" +class Exception; + +using namespace std; +using namespace Qt; + +/* NOTES : + + - A GroupInterface instance can be obtained by linking it to an interface of an inner block, via a + contextual menu that appears when right clicking on the inner interface item. + Thus, it is impossible to create a "bypass": an input group interface, directly linked to an output + group interface. + - the direction (in/out/bi) of this interface is the same as that of the inner interface. + - except for the top group, a correct design will always have group interfaces that have + both connectedTo and connectedFrom containings something. Indeed, a group interface must be seen + as a tunnel to communicate data from outside the group to blocks within the group. + Thus, an input group interface has connectedFrom refering to an output interface of a block outside the group + and connectedTo listing input interfaces of blocks within the group. + An output group interface has connectedFrom refering to an output interface of a bock within the group, + and connectedTo listing input interface of blocks outside the group. + + */ + + +class GroupInterface : public ConnectedInterface { + +public : + GroupInterface(AbstractBlock* _owner, const QString& _name, int _direction, int _level = AbstractInterface::Basic) throw (Exception); + + // getters + + // setters + + // testers + bool isGroupInterface(); + bool canConnectTo(AbstractInterface* iface); + bool canConnectFrom(AbstractInterface* iface); + + // others + AbstractInterface *clone(); + void connectionsValidation(QStack *interfacetoValidate, QList *validatedInterfaces) throw(Exception); + +}; + +#endif // __GROUPINTERFACE_H__ diff --git a/GroupItem.cpp b/GroupItem.cpp new file mode 100644 index 0000000..04d7bca --- /dev/null +++ b/GroupItem.cpp @@ -0,0 +1,581 @@ +#include "GroupItem.h" + +#include "ConnectionItem.h" +#include "InterfaceItem.h" +#include "Dispatcher.h" +#include "Parameters.h" +#include "BoxItem.h" +#include "AbstractBlock.h" +#include "AbstractInterface.h" +#include "ConnectedInterface.h" +#include "GroupScene.h" + + +GroupItem::GroupItem(BoxItem *_parentItem, + AbstractBlock *_refBlock, + Dispatcher *_dispatcher, + Parameters *_params) throw(Exception) :AbstractBoxItem( _refBlock, _dispatcher, _params) { + + parentItem = _parentItem; + + /* + minimumBoxWidth = nameWidth+2*nameMargin; + minimumBoxHeight = 100; + boxHeight = minimumBoxHeight; + boxWidth = minimumBoxWidth; + */ + rectTitle = QRectF(0,-(nameHeight+2*nameMargin),nameWidth+2*nameMargin,nameHeight+2*nameMargin); + /* + totalHeight = boxHeight + rectTitle.height(); + totalWidth = boxWidth; +*/ + selected = false; + + + setZValue(-100); + + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); + + updateGeometry(); + QPointF initPos = QPointF(0.0,0.0) - originPoint; + setPos(initPos); + cout << "total size of group: " << totalWidth << "," << totalHeight << endl; + cout << "pos in scene: " << x() << "," << y() << endl; +} + +GroupItem::~GroupItem() { + // since the reference block is nowhere referenced except in this class, it must be deleted here + delete refBlock; +} + +bool GroupItem::isGroupItem() { + return true; +} + +BoxItem* GroupItem::getParentItem() { + return parentItem; +} + +void GroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + if(boxWidth > 0 && boxHeight > 0){ + if(selected) + painter->setPen(Qt::red); + else + painter->setPen(Qt::black); + + painter->drawRect(0,0,boxWidth,boxHeight); + painter->drawRect(rectTitle); + painter->drawText(rectTitle,Qt::AlignCenter | Qt::TextWordWrap,refBlock->getName()); + } + foreach(InterfaceItem *item, interfaces){ + item->paint(painter); + } +} + +/* NOTE: + Each time a new block is added in a GroupItem, it is placed + at an absolute position of (0,0) within the GroupItem. (NB: the absolute + position is computed by item.pos()+item.getOriginPoint()). + Thus, there are 3 cases : + - a single block is within the GroupItem + - several blocks already placed and a new one + - several blocks already placed and one is moving. + + */ +void GroupItem::updateMinimumSize() { + + // compute place taken by blocks. + int marginConn = 2*(params->arrowWidth+params->arrowLineLength); + if (rectTitle.width() > 2*marginConn) { + minimumBoxWidth = rectTitle.width(); + } + else { + minimumBoxWidth = 2*marginConn; + } + minimumBoxHeight = 2*marginConn; + + if (getScene() == NULL) return; + + QList blocks = getScene()->getBlockItems(); + if(blocks.length() > 0) { + // first, search for blocks that are at (0,0) + int xMaxZero = 0; + int yMaxZero = 0; + int xMax = 0; + int yMax = 0; + bool isZeroBlocks = false; + bool isOtherBlocks = false; + foreach(BoxItem* item, blocks) { + QPointF p = item->pos() + item->getOriginPoint(); + if ((p.x()==0.0) && (p.y()==0.0)) { + isZeroBlocks = true; + if (item->getTotalWidth() > xMaxZero) { + xMaxZero = item->getTotalWidth(); + } + if (item->getTotalHeight() > yMaxZero) { + yMaxZero = item->getTotalHeight(); + } + } + else { + isOtherBlocks = true; + if(p.x()+item->getTotalWidth() > xMax) { + xMax = p.x()+item->getTotalWidth(); + } + if(p.y()+item->getTotalHeight() > yMax) { + yMax = p.y()+item->getTotalHeight(); + } + } + } + if (isZeroBlocks) { + if (!isOtherBlocks) { + minimumBoxWidth = xMaxZero+2*marginConn; + minimumBoxHeight = yMaxZero+2*marginConn; + } + else { + if (xMaxZero+marginConn > xMax) { + minimumBoxWidth = xMaxZero+2*marginConn; + } + else { + minimumBoxWidth = xMax+marginConn; + } + if (yMaxZero+marginConn > yMax) { + minimumBoxHeight = yMaxZero+2*marginConn; + } + else { + minimumBoxHeight = yMax+marginConn; + } + } + } + else { + minimumBoxWidth = xMax+marginConn; + minimumBoxHeight = yMax+marginConn; + } + } + //cout << "min group size: " << minimumBoxWidth << "," << minimumBoxHeight << endl; +} + +void GroupItem::updateShape() { + updateGeometry(); +} + +bool GroupItem::updateGeometry(ChangeType type) { + + QPointF oldOrigin = originPoint; + QSize oldSize(totalWidth,totalHeight); + + updateMinimumSize(); + bool boxSizeChanged = false; + if (boxWidth < minimumBoxWidth) { + boxWidth = minimumBoxWidth; + boxSizeChanged = true; + } + if (boxHeight < minimumBoxHeight) { + boxHeight = minimumBoxHeight; + boxSizeChanged = true; + } + if (boxSizeChanged) { + updateInterfacesAndConnections(); + } + + // compute the max. width of interfaces' name for 4 orientations. + int maxSouth = 0; + int maxNorth = 0; + int maxEast = 0; + int maxWest = 0; + int ifaceWidth = 0; + + foreach(InterfaceItem* iface, interfaces) { + ifaceWidth = iface->getNameWidth(); + if (iface->getOrientation() == Parameters::South) { + if (ifaceWidth > maxSouth) maxSouth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength; + } + else if (iface->getOrientation() == Parameters::North) { + if (ifaceWidth > maxNorth) maxNorth = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength; + } + else if (iface->getOrientation() == Parameters::East) { + if (ifaceWidth > maxEast) maxEast = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength; + } + else if (iface->getOrientation() == Parameters::West) { + if (ifaceWidth > maxWest) maxWest = ifaceWidth+ifaceMargin+params->arrowWidth+params->arrowLineLength; + } + } + double x = 0.0; + double y = 0.0; + totalWidth = boxWidth+maxEast; + totalHeight = boxHeight+maxSouth; + + if (maxWest > 0) { + x -= maxWest; + totalWidth += maxWest; + } + if (maxNorth > (nameHeight+2*nameMargin)) { + y -= maxNorth; + totalHeight += maxNorth; + } + else { + y -= nameHeight+2*nameMargin; + totalHeight += nameHeight+2*nameMargin; + } + QSizeF newSize(totalWidth,totalHeight); + originPoint.setX(x); + originPoint.setY(y); + + if ((boxSizeChanged) || (newSize != oldSize) || (originPoint != oldOrigin)) { + //cout << "must change group item shape" << endl; + prepareGeometryChange(); + return true; + } + return false; +} + +void GroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + + if(params->editState == Parameters::EditGroupMove) { + QPointF absPos = currentPosition + originPoint; + int gapX = event->scenePos().x() - cursorPosition.x(); + int gapY = event->scenePos().y() - cursorPosition.y(); + + //cout << "block abs. pos: " << absPos.x() << "," << absPos.y() << " | "; + //cout << "block current. pos: " << currentPosition.x() << "," << currentPosition.y() << " | "; +/* + if (absPos.x()+gapX < 0) { + gapX = -absPos.x(); + } + if (absPos.y()+gapY < 0) { + gapY = -absPos.y(); + } + */ + //cout << "gap: " << gapX << "," << gapY << " | "; + //cout << "scene: " << getScene()->sceneRect().x() << "," << getScene()->sceneRect().y() << endl; + QPointF gap(gapX,gapY); + currentPosition = currentPosition+gap; + setPos(currentPosition); + cursorPosition = event->scenePos(); + } + else if(params->editState == Parameters::EditGroupResize) { + + int gapX = event->scenePos().x() - cursorPosition.x(); + int gapY = event->scenePos().y() - cursorPosition.y(); + //cout << "gap: " << gapX << "," << gapY << endl; + switch(currentBorder){ + case BorderEast: { + if(boxWidth+gapX > minimumBoxWidth){ + boxWidth += gapX; + } + break; + } + case BorderSouth: { + if(boxHeight+gapY > minimumBoxHeight){ + boxHeight += gapY; + } + break; + } + case CornerSouthEast: { + if(boxWidth+gapX > minimumBoxWidth){ + boxWidth += gapX; + } + if(boxHeight+gapY > minimumBoxHeight){ + boxHeight += gapY; + } + break; + } + case NoBorder: + cout << "abnormal case while resizing block" << endl; + break; + } + updateGeometry(); + /* + // recompute the geometry of the block + updateGeometry(); + // update all interfaces positions + foreach(InterfaceItem *item, interfaces){ + item->updatePosition(); + } + // update all connections from/to this block + foreach(ConnectionItem *item, getScene()->getConnectionItems()){ + if ((item->getFromInterfaceItem()->getOwner() == this) || (item->getToInterfaceItem()->getOwner() == this)) { + item->setPathes(); + } + } + */ + cursorPosition = event->scenePos(); + } + else if(params->editState == Parameters::EditInterfaceMove) { + prepareGeometryChange(); + deplaceInterface(event->pos()); + // recompute the geometry of the block + updateGeometry(); + // update connection from/to the selected interface + foreach(ConnectionItem *item, getScene()->getConnectionItems()){ + if ((item->getFromInterfaceItem() == currentInterface) || (item->getToInterfaceItem() == currentInterface)) { + item->setPathes(); + } + } + update(); + } +} + +void GroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + + QPointF pos = event->pos(); + qreal x = pos.x(); + qreal y = pos.y(); + + QGraphicsItem::mousePressEvent(event); + + if(event->button() == Qt::RightButton) return; + + int mode = getScene()->getEditionMode(); + + dispatcher->setCurrentGroupWidget(getScene()->getGroupWindow()); + + /* NOTE : commneted because group interface are normally + created and the connected directly to a block within + the group. Furthermore, there can be a single connection + from a groupe interface. + + if ((mode == GroupScene::AddConnection) && (params->cursorState == Parameters::CursorOnInterface)) { + InterfaceItem *inter = getInterfaceFromCursor(x,y); + if (inter != NULL) { + + if (params->editState == Parameters::EditNoOperation) { + getScene()->setSelectedInterface(1,inter); + params->setEditState(Parameters::EditStartConnection); + } + else if (params->editState == Parameters::EditStartConnection) { + if (inter == getScene()->getSelectedInterface(1)) { + params->setEditState(Parameters::EditAbortConnection); + } + else { + getScene()->setSelectedInterface(2,inter); + params->setEditState(Parameters::EditCloseConnection); + } + } + } + } + */ + if (mode == GroupScene::ItemEdition) { + + if (params->cursorState == Parameters::CursorOnInterface) { + InterfaceItem *inter = getInterfaceFromCursor(x,y); + if (inter != NULL) { + currentInterface = inter; + params->setEditState(Parameters::EditInterfaceMove); + } + } + else if (params->cursorState == Parameters::CursorInGroupTitle) { + params->setEditState(Parameters::EditGroupMove); + cursorPosition = event->scenePos(); + } + else if (params->cursorState == Parameters::CursorOnBorder) { + setFlag(ItemIsMovable, false); + cursorPosition = event->scenePos(); + params->setEditState(Parameters::EditGroupResize); + } + } +} + +void GroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + + int mode = getScene()->getEditionMode(); + + /* NOTE : commneted because group interface are normally + created and the connected directly to a block within + the group. Furthermore, there can be a single connection + from a groupe interface. + + if (mode == GroupScene::AddConnection) { + + if (params->editState == Parameters::EditStartConnection) { + params->setEditState(Parameters::EditStartConnection); + InterfaceItem* iface = getScene()->getSelectedInterface(1); + iface->selected = true; + update(iface->boundingRect()); + } + else if (params->editState == Parameters::EditAbortConnection) { + InterfaceItem* iface = getScene()->getSelectedInterface(1); + iface->selected = false; + update(iface->boundingRect()); + getScene()->setSelectedInterface(1,NULL); + params->setEditState(Parameters::EditNoOperation); + } + else if (params->editState == Parameters::EditCloseConnection) { + InterfaceItem* iface1 = getScene()->getSelectedInterface(1); + InterfaceItem* iface2 = getScene()->getSelectedInterface(2); + bool ok = dispatcher->connect(iface1,iface2); + if (ok) { + iface1->selected = false; + update(iface1->boundingRect()); + getScene()->setSelectedInterface(1,NULL); + getScene()->setSelectedInterface(2,NULL); + params->setEditState(Parameters::EditNoOperation); + } + } + } + */ + if (mode == GroupScene::ItemEdition) { + currentInterface = NULL; + setFlag(ItemIsMovable, true); + params->editState = Parameters::EditNoOperation; + } + QGraphicsItem::mouseReleaseEvent(event); +} + +void GroupItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + QPointF pos = event->pos(); + qreal x = pos.x(); + qreal y = pos.y(); + currentBorder = NoBorder; + int mode = getScene()->getEditionMode(); + + if (mode == GroupScene::AddConnection) { + InterfaceItem* iface = getInterfaceFromCursor(x,y); + if (iface != NULL) { + params->cursorState = Parameters::CursorOnInterface; + setCursor(Qt::PointingHandCursor); + } + else { + params->cursorState = Parameters::CursorNowhere; + setCursor(Qt::ArrowCursor); + } + } + else if (mode == GroupScene::ItemEdition) { + int marginE = 5; + int marginS = 5; + + InterfaceItem* iface = getInterfaceFromCursor(x,y); + if (iface != NULL) { + params->cursorState = Parameters::CursorOnInterface; + setCursor(Qt::PointingHandCursor); + } + else if ((x>boxWidth-marginE)&&(xcursorState = Parameters::CursorOnBorder; + + if ((y>boxHeight-2*marginS)&&(yboxHeight-marginS)&&(ycursorState = Parameters::CursorOnBorder; + + if ((x>boxWidth-2*marginE)&&(xcursorState = Parameters::CursorInGroupTitle; + setCursor(Qt::OpenHandCursor); + } + else { + params->cursorState = Parameters::CursorNowhere; + setCursor(Qt::ArrowCursor); + } + } + } + QGraphicsItem::hoverMoveEvent(event); +} + +void GroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { + QMenu menu; + QAction* showProperties = NULL; + QAction* removeAction = NULL; + QAction* renameAction = NULL; + + InterfaceItem* ifaceItem = getInterfaceFromCursor(event->pos().x(), event->pos().y()); + if( ifaceItem != NULL){ + showProperties = menu.addAction("Show properties"); + renameAction = menu.addAction("Rename"); + menu.addSeparator(); + /* CAUTION : the interface can be removed only if its + connected to only one side, i.e. connectedFrom is null + or connectedTo is empty. + + */ + ConnectedInterface* ref = ifaceItem->refInter; + if ((!ref->isConnectedFrom()) || (!ref->isConnectedTo())) { + removeAction = menu.addAction("Remove"); + } + } + else { + renameAction = menu.addAction("Rename"); + } + QAction* selectedAction = menu.exec(event->screenPos()); + + if(selectedAction == NULL) return; + + if(selectedAction == renameAction){ + if(ifaceItem != NULL) + dispatcher->rename(ifaceItem); + else + dispatcher->rename(this); + } + else if(selectedAction == showProperties){ + dispatcher->showProperties(ifaceItem); + } + else if (selectedAction == removeAction) { + dispatcher->removeGroupInterface(ifaceItem); + } +} + +InterfaceItem* GroupItem::isHoverInterface(QPointF point) { + foreach(InterfaceItem *inter, interfaces){ + if(inter->boundingRect().contains(point)) + return inter; + } + return NULL; +} + +void GroupItem::save(QXmlStreamWriter &writer) { + + writer.writeStartElement("group_item"); + + QString attrId = QString::number(id); + QString attrName(getRefBlock()->getName()); + QString attrUpperItem = QString::number(-1); + if(parentItem != NULL){ + attrUpperItem = QString::number(parentItem->getId()); + } + QString attrPos = QString::number(pos().x()).append(",").append(QString::number(pos().y())); + QString attrDim = QString::number(getWidth()).append(",").append(QString::number(getHeight())); + + + writer.writeAttribute("id",attrId); + writer.writeAttribute("upper_item",attrUpperItem); + writer.writeAttribute("name",attrName); + writer.writeAttribute("position", attrPos); + writer.writeAttribute("dimension", attrDim); + + writer.writeStartElement("group_ifaces"); + + writer.writeAttribute("count",QString::number(interfaces.length())); + + foreach(InterfaceItem *item, interfaces){ + writer.writeStartElement("group_iface"); + + writer.writeAttribute("id",QString::number(item->getId())); + writer.writeAttribute("name",item->getName()); + writer.writeAttribute("level",QString(item->refInter->getLevelString())); + writer.writeAttribute("direction",QString(item->refInter->getDirectionString())); + writer.writeAttribute("orientation",item->getStrOrientation()); + writer.writeAttribute("position",QString::number(item->getPositionRatio())); + + writer.writeEndElement(); + } + + writer.writeEndElement();// + + writer.writeEndElement();// +} diff --git a/GroupItem.h b/GroupItem.h new file mode 100644 index 0000000..3882a60 --- /dev/null +++ b/GroupItem.h @@ -0,0 +1,73 @@ +#ifndef __GROUPITEM_H__ +#define __GROUPITEM_H__ + +#include + +#include +#include + +#include "AbstractBoxItem.h" +class AbstractBoxItem; + +class BoxItem; +class InterfaceItem; +class Dispatcher; +class Parameters; + +#include "Exception.h" + +using namespace std; +using namespace Qt; + +class GroupItem : public AbstractBoxItem { + +public: + /* CAUTION : the parentItem of a group block IS NOT the group item of the parent scene. It is a BlockItem that is + wihtin the parent scene. It is used when interfaceItem are added to the current GroupItem: they must be also added + to the parent BlockItem. + + NB : this yields a problem when loading a project because scenes are created before creating group and then block. + thus, the parentItem must be initialized afterward when all block items have been created. + + */ + GroupItem(BoxItem* _parentItem, AbstractBlock *_refBlock, Dispatcher *_dispatcher, Parameters *_params) throw(Exception); + ~GroupItem(); + + // getters + BoxItem* getParentItem(); + + // setters + + // testers + bool isGroupItem(); + + // others + void updateShape(); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + void save(QXmlStreamWriter& writer); + +protected: + + void updateMinimumSize(); // modify the minimum size + bool updateGeometry(ChangeType type); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); + + + +private: + /* NOTE : parentItem attribute is never NULL except for the top GroupItem + in the top scene + */ + BoxItem* parentItem; + QRectF rectTitle; + + + InterfaceItem *isHoverInterface(QPointF point); +}; + +#endif // __GROUPITEM_H__ diff --git a/GroupScene.cpp b/GroupScene.cpp new file mode 100644 index 0000000..7ba8c9d --- /dev/null +++ b/GroupScene.cpp @@ -0,0 +1,215 @@ +#include "GroupScene.h" + +#include "Dispatcher.h" +#include "Parameters.h" +#include "GroupWidget.h" +#include "GroupItem.h" +#include "BoxItem.h" +#include "ConnectionItem.h" +#include "InterfaceItem.h" +#include "AbstractBlock.h" + +GroupScene::GroupScene(GroupScene *_parentScene, GroupWidget *_window, Dispatcher* _dispatcher, Parameters* _params, bool _topScene, QObject *parent) : QGraphicsScene(parent) { + dispatcher = _dispatcher; + params = _params; + parentScene = _parentScene; + if (parentScene != NULL) { + parentScene->addChildScene(this); + } + window = _window; + groupItem = NULL; + id = -1; + topScene = _topScene; + editMode = InitState; + + selectedInterfaces[0] = NULL; + selectedInterfaces[1] = NULL; +} + +GroupScene::~GroupScene() { + blockItems.clear(); + connectionItems.clear(); + groupItem = NULL; +} + +void GroupScene::setSelectedInterface(int id, InterfaceItem* iface) { + if ((id < 1)|| (id > 2)) return; + selectedInterfaces[id-1] = iface; +} + +InterfaceItem* GroupScene::getSelectedInterface(int id) { + if ((id < 1)|| (id > 2)) return NULL; + return selectedInterfaces[id-1]; +} + +QList GroupScene::getSelectedBlocks() { + QList lst; + foreach(BoxItem *item, blockItems){ + if (item->isSelected()){ + lst.append(item); + } + } + return lst; +} + +int GroupScene::setItemsId(int countInit) { + int counter = countInit; + groupItem->setId(counter++); + foreach(BoxItem *item, blockItems){ + item->setId(counter++); + } + return counter; +} + +int GroupScene::setInterfacesId(int countInit) { + int counter = countInit; + foreach(InterfaceItem* inter, groupItem->getInterfaces()){ + inter->setId(counter++); + } + foreach(BoxItem *item, blockItems){ + foreach(InterfaceItem* inter, item->getInterfaces()){ + inter->setId(counter++); + } + } + return counter; +} + +QList GroupScene::getGroupAndBlocks() { + + QList lst; + lst.append(groupItem); + foreach(BoxItem *item, blockItems){ + lst.append(item); + } + return lst; +} + +void GroupScene::createBlockItem(AbstractBlock *block) { + + BoxItem* blockItem = new BoxItem(block,dispatcher,params,groupItem); + blockItem->setZValue(1); + addBlockItem(blockItem); +} + +void GroupScene::addBlockItem(BoxItem* item) { + // add item from the viewport + //addItem(item); + // add item from the QList + blockItems.append(item); + // repainting the group + groupItem->updateShape(); + // center the new block + QPointF newPos((groupItem->getWidth()-item->getTotalWidth())/2.0, (groupItem->getHeight()-item->getTotalHeight())/2.0); + newPos = newPos-item->getOriginPoint(); + item->moveTo(newPos); +} + +void GroupScene::removeBlockItem(BoxItem* item) { + // remove item from the viewport + removeItem(item); + // remove item from the QList + blockItems.removeAll(item); + // repainting the group + groupItem->updateShape(); +} + +void GroupScene::createConnectionItem(InterfaceItem *iface1, InterfaceItem *iface2) { + ConnectionItem* conn = new ConnectionItem(iface1,iface2, dispatcher, params, groupItem); + addConnectionItem(conn); +} + +ConnectionItem* GroupScene::searchConnectionItem(InterfaceItem *iface1, InterfaceItem *iface2) { + foreach(ConnectionItem* conn , connectionItems) { + if ( ((conn->getFromInterfaceItem() == iface1) && (conn->getToInterfaceItem() == iface2)) || + ((conn->getFromInterfaceItem() == iface2) && (conn->getToInterfaceItem() == iface1))) { + return conn; + } + } +} + +void GroupScene::addConnectionItem(ConnectionItem* item) { + // add item from the viewport + //addItem(item); + // add item from the QList + connectionItems.append(item); +} + +void GroupScene::removeConnectionItem(ConnectionItem* item) { + // remove item from the viewport + removeItem(item); + // remove item from the QList + connectionItems.removeAll(item); +} + +void GroupScene::setGroupItem(GroupItem *group) { + if ((groupItem == NULL) && (group != NULL)) { + groupItem = group; + addItem(group); + } +} + +void GroupScene::removeGroupItem() { + // remove item from the viewport + removeItem(groupItem); + groupItem = NULL; +} + +QList GroupScene::getInterfaceConnections(InterfaceItem *item) { + QList list; + foreach(ConnectionItem *conn, connectionItems){ + if(conn->getFromInterfaceItem() == item || conn->getToInterfaceItem() == item){ + list.append(conn); + } + } + return list; +} + +void GroupScene::unselecteInterfaces() { + + if (selectedInterfaces[0] != NULL) { + selectedInterfaces[0]->selected = false; + selectedInterfaces[0] == NULL; + } + if (selectedInterfaces[1] != NULL) { + selectedInterfaces[1]->selected = false; + selectedInterfaces[1] == NULL; + } +} + +void GroupScene::updateConnectionItemsShape() { + + foreach(ConnectionItem* conn, connectionItems){ + conn->setPathes(); + } +} + +void GroupScene::save(QXmlStreamWriter &writer) { + writer.writeStartElement("scene"); + writer.writeAttribute("id",QString::number(id)); + groupItem->save(writer); + + writer.writeStartElement("block_items"); + + QList functionalBlocks; + QList groupBlocks; + + foreach(BoxItem *item, blockItems){ + if(item->getRefBlock()->isFunctionalBlock()){ + functionalBlocks.append(item); + } else if(item->getRefBlock()->isGroupBlock()){ + groupBlocks.append(item); + } + } + writer.writeAttribute("functional_count",QString::number(functionalBlocks.length())); + writer.writeAttribute("group_count",QString::number(groupBlocks.length())); + + foreach(BoxItem* item, functionalBlocks) { + item->save(writer); + } + foreach(BoxItem* item, groupBlocks) { + item->save(writer); + } + writer.writeEndElement(); // block_items + writer.writeEndElement(); // scene +} + diff --git a/GroupScene.h b/GroupScene.h new file mode 100644 index 0000000..8561482 --- /dev/null +++ b/GroupScene.h @@ -0,0 +1,110 @@ +#ifndef __GROUPSCENE_H__ +#define __GROUPSCENE_H__ + +#include +#include +#include + +class Dispatcher; +class Parameters; +class AbstractBlock; +class GroupWidget; +class GroupItem; +class BoxItem; +class AbstractBoxItem; +class ConnectionItem; +class InterfaceItem; + +using namespace std; +using namespace Qt; + +/* NOTES : + + - A GroupScene is composed of a single GroupItem that contains BlockItem and ConnectionItem + The GroupItem is stored in the mainGroup attribute + + - A GroupScene is instanciated whenever there is a GroupItem that must be created, i.e. + for the top scene or for subgroups. + + - This class is a subclass of QGraphicsScene by convenience but it's goal is more to list + the different inner items. Thus, all operations that add/remove items to the scene will also + add them in the QList + */ + +class GroupScene : public QGraphicsScene { + +public: + + /* edition mode of the window: + - AddBlock: can only add blocks to the scene + - AddConnection: can only add connections to the scene + - AddGroup: while a new group (empty or from selected blocks) is created + - ItemEdtion: can move/resize blocks/interfaces, remove blocks/interface/group, ... + */ + enum EditMode { InitState, AddBlock, AddConnection, AddGroup, ItemEdition }; + + GroupScene(GroupScene* _parentScene, GroupWidget* _window, Dispatcher* _dispatcher, Parameters* _params, bool topScene = false, QObject *parent = 0); + ~GroupScene(); + + // attributes getters + inline GroupItem* getGroupItem() {return groupItem;} + inline QList getBlockItems() { return blockItems; } + inline QList getConnectionItems() { return connectionItems; } + inline QList getChildrenScene() { return childrenScene; } + inline GroupWidget* getGroupWindow() { return window; } + inline int getId() { return id; } + inline EditMode getEditionMode() { return editMode; } + InterfaceItem* getSelectedInterface(int id); + + // attributes setters + inline void setWindow(GroupWidget* _window) { window = _window; } + void setGroupItem(GroupItem* group); + inline void setId(int id) { this->id = id; } + inline void setEditionMode(EditMode mode) { editMode = mode; } + void setSelectedInterface(int id, InterfaceItem* iface); + + // attributes testers + inline bool isTopScene() { return topScene; } + + + // others + void createBlockItem(AbstractBlock* block); + void addBlockItem(BoxItem* item); + void removeBlockItem(BoxItem* item); + void createConnectionItem(InterfaceItem* iface1, InterfaceItem* iface2); + ConnectionItem* searchConnectionItem(InterfaceItem* iface1, InterfaceItem* iface2); + void addConnectionItem(ConnectionItem* item); + void removeConnectionItem(ConnectionItem* item); + void removeGroupItem(); + inline void addChildScene(GroupScene* child) { childrenScene.append(child); } + void unselecteInterfaces(); + + QList getGroupAndBlocks(); + QList getSelectedBlocks(); + + QList getInterfaceConnections(InterfaceItem *item); + + int setItemsId(int countInit=1); + int setInterfacesId(int countInit=1); + + void updateConnectionItemsShape(); + + void save(QXmlStreamWriter& writer); + +private: + Dispatcher *dispatcher; + Parameters *params; + GroupScene* parentScene; // the parnet scene, =NULL for top scene + GroupWidget* window; // the GroupWindow that contains that scene + int id; + GroupItem *groupItem; // mandatory to be an instance of GroupItem. + QList connectionItems; + QList blockItems; + QList childrenScene; + bool topScene; + EditMode editMode; + InterfaceItem* selectedInterfaces[2]; // selected iface 1 in AddConnection mode + +}; + +#endif // __GROUPSCENE_H__ diff --git a/GroupWidget.cpp b/GroupWidget.cpp new file mode 100644 index 0000000..1446a13 --- /dev/null +++ b/GroupWidget.cpp @@ -0,0 +1,279 @@ +#include "GroupWidget.h" + +#include "Dispatcher.h" +#include "Parameters.h" + +#include "GroupScene.h" +#include "GroupBlock.h" +#include "BoxItem.h" +#include "GroupItem.h" +#include "ConnectionItem.h" +#include "Graph.h" + +GroupWidget::GroupWidget(GroupWidget *_upperGroup, Dispatcher *_dispatcher, + Parameters *_params, + QWidget *parent) : QWidget(parent) { + upperGroup = _upperGroup; + dispatcher = _dispatcher; + params = _params; + if (upperGroup == NULL) { + topGroup = true; + scene = new GroupScene(NULL, this, dispatcher, params, true); + } + else { + topGroup = true; + scene = new GroupScene(upperGroup->getScene(), this, dispatcher, params, false); + } + + layout = new QGridLayout; + + QGraphicsView *view = new QGraphicsView(scene); + layout->addWidget(view,1,0,1,3); + + createActions(); + createToolbar(); + setLayout(layout); + setFocusPolicy(Qt::StrongFocus); + setFocus(); + + scene->setEditionMode(GroupScene::ItemEdition); + updateBlockButton(); + +} + +GroupWidget::~GroupWidget(){} + +void GroupWidget::changeConnectionMode(int mode) { + /* + QPalette pal = buttonNewConnection->palette(); + + if(mode == -1){ + + if(params->sceneMode != Parameters::EditOnConnection){ + params->sceneMode = Parameters::EditOnConnection; + pal.setColor(QPalette::Button, QColor(Qt::lightGray)); + + } else { + params->sceneMode = Parameters::EditNoOperation; + pal.setColor(QPalette::Button, QColor("#edeceb")); + dispatcher->unselectAllInterfaces(); + } + } else if(mode == Parameters::EditOnConnection){ + params->sceneMode = Parameters::EditOnConnection; + pal.setColor(QPalette::Button, QColor(Qt::lightGray)); + } else { + params->sceneMode = Parameters::EditNoOperation; + pal.setColor(QPalette::Button, QColor("#edeceb")); + } + dispatcher->unselectAllInterfaces(); + buttonNewConnection->setAutoFillBackground(true); + buttonNewConnection->setPalette(pal); + buttonNewConnection->update(); + */ +} + + +void GroupWidget::enableGroupButton(bool b) { + newGroupAct->setEnabled(b); +} + + +void GroupWidget::mousePressEvent(QMouseEvent *e) { + dispatcher->setCurrentGroupWidget(this); + QWidget::mousePressEvent(e); +} + +void GroupWidget::focusInEvent(QFocusEvent *e) { + /* + if(params->currentWindow != this){ + params->setCurrentWindow(this); + changeConnectionMode(false); + } + */ +} + +void GroupWidget::closeEvent(QCloseEvent *e) { + clearFocus(); + focusNextChild(); +} + + +void GroupWidget::createActions() { + + butAddConnection = new QToolButton(this); + butAddConnection->setIcon(QPixmap::fromImage(QImage("icons/add_connection.png"))); + butAddConnection->setToolTip("Adding connections"); + QPalette pal = butAddConnection->palette(); + butBaseColor = pal.color(QPalette::Button); + connect(butAddConnection, SIGNAL(clicked()), this, SLOT(slotAddConnection())); + + butEdit = new QToolButton(this); + butEdit->setIcon(QPixmap::fromImage(QImage("icons/edit_block.png"))); + butEdit->setToolTip("Edit items"); + connect(butEdit, SIGNAL(clicked()), this, SLOT(slotEdit())); + + copyBlockAct = new QAction(tr("&Copy block"), this); + copyBlockAct->setIcon(QPixmap::fromImage(QImage("icons/copy.png"))); + copyBlockAct->setStatusTip(tr("Copy the selected block")); + connect(copyBlockAct, SIGNAL(triggered()), this, SLOT(slotCopyBlock())); + + newEmptyGroupAct = new QAction(tr("&Create a new empty group"), this); + newEmptyGroupAct->setIcon(QPixmap::fromImage(QImage("icons/add_group_void.png"))); + newEmptyGroupAct->setStatusTip(tr("Create a new empty group")); + connect(newEmptyGroupAct, SIGNAL(triggered()), this, SLOT(slotNewEmptyGroup())); + + newGroupAct = new QAction(tr("&Create a new group"), this); + newGroupAct->setIcon(QPixmap::fromImage(QImage("icons/add_group_select.png"))); + newGroupAct->setStatusTip(tr("Create a new group")); + newGroupAct->setDisabled(true); + connect(newGroupAct, SIGNAL(triggered()), this, SLOT(slotNewGroup())); + + deleteAct = new QAction(tr("&Delete selected elements"), this); + deleteAct->setIcon(QPixmap::fromImage(QImage("icons/delete.png"))); + deleteAct->setStatusTip(tr("Delete selected elements")); + connect(deleteAct, SIGNAL(triggered()), this, SLOT(slotDeleteItems())); + + selectAllAct = new QAction(tr("&Select all elements"), this); + selectAllAct->setIcon(QPixmap::fromImage(QImage("icons/delete.png"))); + selectAllAct->setStatusTip(tr("Select all elements")); + connect(selectAllAct, SIGNAL(triggered()), this, SLOT(slotSelectAll())); + + unselectAllAct = new QAction(tr("&unselect all elements"), this); + unselectAllAct->setIcon(QPixmap::fromImage(QImage("icons/delete.png"))); + unselectAllAct->setStatusTip(tr("Unselect all elements")); + connect(unselectAllAct, SIGNAL(triggered()), this, SLOT(slotUnselectAll())); +} + +void GroupWidget::createToolbar() { + toolbarEditMode = new QToolBar(tr("Mode")); + toolbarAdd = new QToolBar(tr("Group")); + toolbarTools = new QToolBar(tr("Tools")); + + toolbarEditMode->addWidget(new QLabel("Mode")); + toolbarTools->addWidget(new QLabel("Tools")); + + toolbarEditMode->addSeparator(); + toolbarTools->addSeparator(); + + toolbarEditMode->addWidget(butAddConnection); + toolbarEditMode->addWidget(butEdit); + + toolbarAdd->addAction(copyBlockAct); + toolbarAdd->addAction(newEmptyGroupAct); + toolbarAdd->addAction(newGroupAct); + + toolbarTools->addAction(deleteAct); + toolbarTools->addAction(selectAllAct); + toolbarTools->addAction(unselectAllAct); + + layout->addWidget(toolbarEditMode,0,0); + layout->addWidget(toolbarAdd,0,1); + layout->addWidget(toolbarTools,0,2); +} + +void GroupWidget::slotEdit() { + dispatcher->unselectAllItems(); + getScene()->setEditionMode(GroupScene::ItemEdition); + updateBlockButton(); +} + +void GroupWidget::slotCopyBlock() { + foreach (BoxItem *item, params->getCurrentScene()->getBlockItems()) { + if(item->isSelected()){ + dispatcher->duplicateBlock(item); + } + } +} + +void GroupWidget::slotAddConnection() { + dispatcher->unselectAllItems(); + getScene()->setEditionMode(GroupScene::AddConnection); + updateBlockButton(); +} + +void GroupWidget::updateBlockButton() { + + // reset all buttons to light gray + QPalette pal = butAddConnection->palette(); + pal.setColor(QPalette::Button, butBaseColor); + + butAddConnection->setAutoFillBackground(true); + butAddConnection->setPalette(pal); + butAddConnection->update(); + butEdit->setAutoFillBackground(true); + butEdit->setPalette(pal); + butEdit->update(); + + // set the good one to dark gray + pal.setColor(QPalette::Button, QColor(Qt::darkGray)); + + if(getScene()->getEditionMode() == GroupScene::AddConnection) { + butAddConnection->setAutoFillBackground(true); + butAddConnection->setPalette(pal); + butAddConnection->update(); + } + else if(getScene()->getEditionMode() == GroupScene::ItemEdition) { + butEdit->setAutoFillBackground(true); + butEdit->setPalette(pal); + butEdit->update(); + } + +} + +void GroupWidget::slotNewEmptyGroup() { + + // creating the GroupBlock in graph model + GroupBlock* groupBlock = params->addGroupBlock(); + // creating the BlockItem in the inner scene + BoxItem* block = new BoxItem(groupBlock, dispatcher, params, scene->getGroupItem()); + + GroupWidget* child = dispatcher->createChildScene(this,block); + child->show(); +} + +void GroupWidget::slotNewGroup() +{ + dispatcher->addNewFullGroup(); +} + +void GroupWidget::slotDeleteItems() { + foreach (BoxItem *item, scene->getBlockItems()) { + if(item->isSelected()){ + dispatcher->removeBlock(item); + } + } + foreach (ConnectionItem *item, scene->getConnectionItems()) { + if(item->isSelected()){ + dispatcher->removeConnection(item); + } + } +} + +void GroupWidget::slotSelectAll() +{ + foreach(QGraphicsItem *item, params->getCurrentScene()->items()){ + if(item->data(0) == "block"){ + BoxItem *b = dynamic_cast(item); + b->setSelected(true); + } else if(item->data(0) == "connection"){ + ConnectionItem *c = dynamic_cast(item); + c->setSelected(true); + } + item->update(item->boundingRect()); + } +} + +void GroupWidget::slotUnselectAll() +{ + foreach(QGraphicsItem *item, params->getCurrentScene()->items()){ + if(item->data(0) == "block"){ + BoxItem *b = dynamic_cast(item); + b->setSelected(false); + } else if(item->data(0) == "connection"){ + ConnectionItem *c = dynamic_cast(item); + c->setSelected(false); + } + + item->update(item->boundingRect()); + } +} diff --git a/GroupWidget.h b/GroupWidget.h new file mode 100644 index 0000000..bfdb78b --- /dev/null +++ b/GroupWidget.h @@ -0,0 +1,85 @@ +#ifndef __GROUPWIDGET_H__ +#define __GROUPWIDGET_H__ + +#include + +class Dispatcher; +class Parameters; +class GroupScene; + + + +class GroupWidget : public QWidget { + Q_OBJECT +public: + + explicit GroupWidget(GroupWidget* _upperGroup, Dispatcher* _dispatcher, Parameters* _params, QWidget *parent = 0); + + // getters + inline GroupScene *getScene() {return scene;} + inline QToolButton* getButtonNewConnection(){return butAddConnection;} + + // testers + inline bool isTopGroup() { return topGroup;} + + // others + void changeConnectionMode(int mode = -1); + + + ~GroupWidget(); + + void enableGroupButton(bool b); + +protected: + void mousePressEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *e); + void closeEvent(QCloseEvent *e); + +private: + GroupWidget* upperGroup; // NB:for convenience. NULL if it contains the top scene + bool topGroup; + + GroupScene *scene; + Dispatcher *dispatcher; + Parameters *params; + + void createActions(); + void createToolbar(); + + QToolButton* butAddConnection; + QToolButton* butEdit; + void updateBlockButton(); + QColor butBaseColor; + + QAction *copyBlockAct; + + QAction *newEmptyGroupAct; + QAction *newGroupAct; + + QAction *deleteAct; + QAction *selectAllAct; + QAction *unselectAllAct; + + QToolBar *toolbarEditMode; + QToolBar *toolbarAdd; + QToolBar *toolbarTools; + + + QGridLayout *layout; + +signals: + +private slots: + void slotCopyBlock(); + void slotAddConnection(); + void slotEdit(); + + void slotNewEmptyGroup(); + void slotNewGroup(); + + void slotDeleteItems(); + void slotSelectAll(); + void slotUnselectAll(); +}; + +#endif // __GROUPWIDGET_H__ diff --git a/InterfaceItem.cpp b/InterfaceItem.cpp new file mode 100644 index 0000000..552e159 --- /dev/null +++ b/InterfaceItem.cpp @@ -0,0 +1,445 @@ +#include "InterfaceItem.h" + +#include "Parameters.h" +#include "GroupInterface.h" +#include "FunctionalInterface.h" +#include "BoxItem.h" + +int InterfaceItem::counter = 0; + +InterfaceItem::InterfaceItem(double _position, + int _orientation, + ConnectedInterface *_refInter, + AbstractBoxItem* _owner, + Parameters* _params){ + positionRatio = _position; + orientation = _orientation; + refInter = _refInter; + + // CAUTION : the owner must add explicitely this item to its interface, calling addInterface() + owner = _owner; + params = _params; + selected = false; + name = refInter->getName(); + QFontMetrics fmName(params->defaultIfaceFont); + nameWidth = fmName.width(name); + nameHeight = fmName.height(); + // by default, only data interface are visible + if (refInter->getPurpose() == AbstractInterface::Data) { + visible = true; + } + else { + visible = false; + } + + this->id = InterfaceItem::counter++; + + updatePosition(); +} + + +InterfaceItem::InterfaceItem(){ + this->id = counter++; +} + +/* boundingRect() : give the bounding rect in the blockitem coord. system */ +QRectF InterfaceItem::boundingRect() const { + + QPointF pointHG; + QSizeF s; + + switch(orientation){ + case Parameters::East : + pointHG = QPointF(originPoint.x(),originPoint.y()-(params->arrowHeight/2.0)); + s = QSizeF(params->arrowWidth+params->arrowLineLength, params->arrowHeight); + break; + case Parameters::North : + pointHG = QPointF(originPoint.x()-(params->arrowHeight/2.0),originPoint.y()-params->arrowWidth-params->arrowLineLength); + s = QSizeF(params->arrowHeight,params->arrowWidth+params->arrowLineLength); + break; + case Parameters::West : + pointHG = QPointF(originPoint.x()-params->arrowLineLength-params->arrowWidth,originPoint.y()-(params->arrowHeight/2.0)); + s = QSizeF(params->arrowWidth+params->arrowLineLength, params->arrowHeight); + break; + case Parameters::South : + pointHG = QPointF(originPoint.x()-(params->arrowHeight/2.0),originPoint.y()); + s = QSizeF(params->arrowHeight, params->arrowWidth+params->arrowLineLength); + break; + default : + pointHG = QPointF(); + s = QSizeF(); + break; + } + + return QRectF(pointHG,s); +} + +void InterfaceItem::paint(QPainter *painter) { + + if(visible) { + + painter->save(); + + if(selected) { + painter->setPen(QPen(Qt::red,2)); + } + else if(refInter->getLevel() == AbstractInterface::Basic) { + painter->setPen(QPen(Qt::darkCyan,1)); + } + else if(refInter->getLevel() == AbstractInterface::Top) { + painter->setPen(QPen(Qt::black,1)); + } + + painter->translate(originPoint); + + switch(orientation) { + case Parameters::North: + painter->rotate(-90); + break; + case Parameters::West: + painter->rotate(180); + break; + case Parameters::South: + painter->rotate(90); + break; + } + + // draw arrows + if(refInter->getDirection() == AbstractInterface::Input) { + painter->drawPath(params->inArrow); + } + else if(refInter->getDirection() == AbstractInterface::Output) { + painter->drawPath(params->outArrow); + } else if(refInter->getDirection() == AbstractInterface::InOut) { + painter->drawPath(params->inArrow); + painter->drawPath(params->outArrow); + } + + // draw names + + // reset to normal if at west + if(orientation == Parameters::West){ + painter->rotate(180); + } + + painter->setFont(params->defaultIfaceFont); + + QFontMetrics fm = painter->fontMetrics(); + int w = nameWidth + owner->getIfaceMargin(); + int h = nameHeight; + + if(orientation == Parameters::West){ + + if(owner->isGroupItem()){ + painter->drawText(-(w+params->arrowWidth+params->arrowLineLength),-h/2,w,h,Qt::AlignLeft | Qt::TextWordWrap, refInter->getName()); + } + else if(owner->isBoxItem()){ + painter->drawText(0,-h/2,w,h,Qt::AlignRight | Qt::TextWordWrap, refInter->getName()); + } + } + else { + + if(owner->isGroupItem()) { + painter->drawText(params->arrowWidth+params->arrowLineLength,-h/2,w,h,Qt::AlignRight | Qt::TextWordWrap, refInter->getName()); + } + else if(owner->isBoxItem()) { + painter->drawText(-w,-h/2,w,h,Qt::AlignLeft | Qt::TextWordWrap, refInter->getName()); + } + } + + painter->restore(); + } +} + +QPointF InterfaceItem::getEndPointInGroup() { + QPointF p; + + if (owner->isGroupItem()) { + p = originPoint; + } + else { + double x = owner->x() + originPoint.x(); + double y = owner->y() + originPoint.y(); + switch(orientation){ + case Parameters::East: + x += params->arrowWidth+params->arrowLineLength; + break; + case Parameters::North: + y -= params->arrowWidth+params->arrowLineLength; + break; + case Parameters::West: + x -= params->arrowWidth+params->arrowLineLength; + break; + case Parameters::South: + y += params->arrowWidth+params->arrowLineLength; + break; + } + p = QPointF(x,y); + } + + //cout << "iface end point in group item: " << p.x() << "," << p.y() << endl; + return p; +} + +void InterfaceItem::setOriginPoint() { + switch(orientation){ + case Parameters::East: + originPoint = QPointF(owner->getWidth(),position); + break; + case Parameters::North: + originPoint = QPointF(position,0); + break; + case Parameters::West: + originPoint = QPointF(0,position); + break; + case Parameters::South: + originPoint = QPointF(position,owner->getHeight()); + break; + } +} + +QString InterfaceItem::getStrOrientation() { + QString str = NULL; + switch(orientation){ + case Parameters::North : + str = QString("north"); + break; + case Parameters::South : + str = QString("south"); + break; + case Parameters::East : + str = QString("east"); + break; + case Parameters::West : + str = QString("west"); + break; + } + + return str; +} + +int InterfaceItem::getIntOrientation(QString str) { + if(str == "west") return Parameters::West; + if(str == "east") return Parameters::East; + if(str == "south") return Parameters::South; + if(str == "north") return Parameters::North; + return -1; +} + + +/* connectWith() : + - modify all necessary attributes in the model to create a connection + between current InterfaceItem and iface. Note that the source and destination + are deduced from the direction (In, Out) and the type of the owner (funcitonal, group) + + CAUTION: No security checks are done. This method must be called only if canConnectWith has been called and returned true. + + NOTE : conditions so that this InterfaceItem can be connected with inter. + (i.e. current one can connect to inter OR inter can connect to current) + + Here are all the possible combinations, depending on the type of the + block/item and direction of the interface, which are : + GI/GB : a GroupItem referencing a GroupBlock (single solution for GI) + BI/FB : a BlockItem referencing a FunctionalBlock + BI/GB : a BlockItem referencing a GroupBlock + + For GI/GB: + - Input can connect with BI/FB or BI/GB Input + - Output can connect with BI/FB or BI/GB Output + + For BI/FB: + - Input can connect with: + GI/GB Input + BI/FB Output + BI/GB Output + - Output can connect with: + GI/GB Output + BI/FB Input + BI/GB Input + + For BI/GB: + - Input can connect with: + GI/GB Input + BI/FB Output + BI/GB Output + - Output can connect with: + GI/GB Output + BI/FB Input + BI/GB Input + + And whatever the case an InOut can only connect with an InOut + We note that: + - the IG does not allow the connect a GI/GB interface to an + interface of another GI/GB, thus the case is not considered above. + - BI/FB and BI/GB are the same. + - the cases where direction are the same only occur when + the 2 items are of different type (GI and BI) + - the cases where directions are different only occur when + the 2 are of both BlockItem + +*/ +bool InterfaceItem::connectWith(InterfaceItem *iface) { + ConnectedInterface* interThis = refInter; // the reference of this + ConnectedInterface* interOther = iface->refInter; // the reference of the other + ConnectedInterface* src = NULL, *dest = NULL; + + if(interThis->getDirection() == AbstractInterface::InOut && interOther->getDirection() == AbstractInterface::InOut){ + /* NOTE: InOut interfaces have both directions and thus are + connected from inter1 to inter2 AND inter2 to inter1 + Another effect is that a InOut can be connected to/from a single + InOut. + */ + if((interThis->getConnectedFrom() == NULL) && (interOther->getConnectedFrom() == NULL)) { + + interOther->connectFrom(interThis); + interOther->getConnectedTo().append(interThis); + interThis->connectFrom(interOther); + interThis->getConnectedTo().append(interOther); + + cout << "connecting 2 InOut"<< endl; + return true; + } + return false; + } + else if (interThis->getDirection() == interOther->getDirection()) { + + // cannot connect GI to GI or 2 BI of the same direction. + if ((getOwner()->isGroupItem()) && (iface->getOwner()->isGroupItem())) return false; + if ((getOwner()->isBoxItem()) && (iface->getOwner()->isBoxItem())) return false; + + if (interThis->getDirection() == AbstractInterface::Input) { // both are inputs + cout << "connecting GI to BI" << endl; + if(getOwner()->isGroupItem()) { + src = interThis; + dest = interOther; + } + else { + src = interOther; + dest = interThis; + } + } + else { // both are outputs + cout << "connecting BO to GO" << endl; + if(getOwner()->isGroupItem()){ + src = interOther; + dest = interThis; + } + else { + src = interThis; + dest = interOther; + } + } + } + else { + if ((getOwner()->isGroupItem()) || (iface->getOwner()->isGroupItem())) return false; + + cout << "connecting BO to BI" << endl; + if(interOther->getDirection() == AbstractInterface::Output) { + src = interOther; + dest = interThis; + } + else { + src = interThis; + dest = interOther; + } + } + + if(dest != NULL && src != NULL){ + // cannot overrive existing connectionFrom + if(dest->getConnectedFrom() == NULL) { + dest->connectFrom(src); + src->connectTo(dest); + return true; + } + else { + return false; + } + } + return false; +} + +void InterfaceItem::unconnectTo(InterfaceItem *iface) +{ + if(iface->refInter->getConnectedFrom() == refInter){ + iface->refInter->connectFrom(NULL); + } + if(iface->refInter->getConnectedTo().contains(refInter)){ + cout << "abnormal case while removing iface conn from " << qPrintable(name) << " to " << qPrintable(iface->name) << endl; + iface->refInter->removeConnectedTo(refInter); + } + if(refInter->getConnectedFrom() == iface->refInter) { + cout << "abnormal case while removing iface conn from " << qPrintable(name) << " to " << qPrintable(iface->name) << endl; + refInter->connectFrom(NULL); + } + if(refInter->getConnectedTo().contains(iface->refInter)){ + refInter->removeConnectedTo(iface->refInter); + } +} + +void InterfaceItem::updatePosition() +{ + if(orientation == Parameters::North || orientation == Parameters::South){ + position = positionRatio * owner->getWidth(); + } else { + position = positionRatio * owner->getHeight(); + } + setOriginPoint(); +} + +void InterfaceItem::addConnectionItem(ConnectionItem* item) { + connections.append(item); +} + +void InterfaceItem::removeConnectionItem(ConnectionItem* item) { + connections.removeOne(item); +} + +QDataStream &operator <<(QDataStream &out, InterfaceItem *i) { + +#ifdef DEBUG_INCLFUN + out.setVersion(QDataStream::Qt_5); + + QByteArray interfaceData; + QDataStream toWrite(&interfaceData, QIODevice::WriteOnly); + + toWrite << i->getId(); + toWrite << i->getName(); + toWrite << i->getPositionRatio(); + toWrite << i->getOrientation(); + + foreach(QGraphicsItem* item, i->params->getCurrentScene()->items()){ + if(item->data(0) == "connection"){ + ConnectionItem *conn = dynamic_cast(item); + if(conn->getFromInterfaceItem() == i || conn->getToInterfaceItem() == i){ + toWrite << conn->getId(); + cout << "id connection : " << conn->getId() << endl; + } + } + } + out << interfaceData; +#endif + return out; +} + +QDataStream &operator >>(QDataStream &in, InterfaceItem &i) { + +#ifdef DEBUG_INCLFUN + in.setVersion(QDataStream::Qt_5); + + int id, orientation; + double positionRatio; + QString name; + + in >> id; + in >> name; + in >> positionRatio; + in >> orientation; + + i.setId(id); + i.setName(name); + i.setPositionRatio(positionRatio); + i.setOrientation(orientation); + i.updatePosition(); +#endif + return in; +} diff --git a/InterfaceItem.h b/InterfaceItem.h new file mode 100644 index 0000000..ce65b9e --- /dev/null +++ b/InterfaceItem.h @@ -0,0 +1,88 @@ +#ifndef __INTERFACEITEM_H__ +#define __INTERFACEITEM_H__ + +#include +#include + +class Parameters; +class ConnectedInterface; +class AbstractBoxItem; +class ConnectionItem; + + +using namespace std; +using namespace Qt; + +class InterfaceItem { + +public: + + + + InterfaceItem(double _position, + int _orientation, + ConnectedInterface* _refInter, + AbstractBoxItem* _owner, + Parameters* _params); + InterfaceItem(); + QRectF boundingRect() const; + void paint(QPainter *painter); + + // getters + inline int getId() { return id; } + inline QString getName() { return name; } + inline double getPositionRatio() { return positionRatio; } + inline double getPosition() { return position; } + inline int getOrientation() { return orientation; } + inline AbstractBoxItem *getOwner() { return owner; } + inline int getNameWidth() { return nameWidth; } + inline int getNameHeight() { return nameHeight; } + QString getStrOrientation(); + static int getIntOrientation(QString str); + QPointF getEndPointInGroup(); + + // setters + void setOriginPoint(); + inline void setId(int id){ this->id = id; } + inline void setName(QString name){ this->name = name; } + inline void setPositionRatio(double ratio) { positionRatio = ratio; } + inline void setOrientation(int _orientation){ orientation = _orientation; } + + // others + void addConnectionItem(ConnectionItem* item); + void removeConnectionItem(ConnectionItem* item); + bool canConnectWith(InterfaceItem* iface); + bool connectWith(InterfaceItem* iface); + void unconnectTo(InterfaceItem *iface); + void updatePosition(); + + AbstractBoxItem* owner; + ConnectedInterface* refInter; + Parameters* params; + bool selected; + bool visible; + + static int counter; + + QList connections; // the connection items that are bounded to this interface item + + +private: + int id; + QString name; + double positionRatio; + int position; // position in pixels on the "orientation side" of the owner + int orientation; // north, south, east, west + QPointF originPoint; // the point where starts the drawing (along the box border) NB : in the owner coordinates + int nameWidth; // the graphical width of the name, computed from default font metrics + int nameHeight; // the graphical height of the name, computed from default font metrics + + friend QDataStream &operator<<(QDataStream &out, InterfaceItem *b); + friend QDataStream &operator>>(QDataStream &in, InterfaceItem &b); +}; + +/* +QDataStream & operator <<(QDataStream &out, InterfaceItem *b); +QDataStream & operator >>(QDataStream &in, InterfaceItem &b); +*/ +#endif diff --git a/InterfacePropertiesWindow.cpp b/InterfacePropertiesWindow.cpp new file mode 100644 index 0000000..2200bf6 --- /dev/null +++ b/InterfacePropertiesWindow.cpp @@ -0,0 +1,30 @@ +#include "InterfacePropertiesWindow.h" + +#include "ConnectedInterface.h" + +InterfacePropertiesWindow::InterfacePropertiesWindow(InterfaceItem *_inter, QWidget *parent) : + QWidget(parent) +{ + inter = _inter; + + layout = new QGridLayout; + + + layout->addWidget(new QLabel("Interface properties"), 0, 0); + layout->addWidget(new QLabel(" "), 1, 0); + + layout->addWidget(new QLabel("Name :"), 2, 0); + layout->addWidget(new QLabel(inter->getName()), 2, 1); + layout->addWidget(new QLabel("Width :"), 3, 0); + layout->addWidget(new QLabel(inter->refInter->getWidth()), 3, 1); + layout->addWidget(new QLabel("Direction :"), 4, 0); + layout->addWidget(new QLabel(inter->refInter->getDirectionString()), 4, 1); + layout->addWidget(new QLabel("Purpose :"), 5, 0); + layout->addWidget(new QLabel(inter->refInter->getPurposeString()), 5, 1); + layout->addWidget(new QLabel("Level :"), 6, 0); + layout->addWidget(new QLabel(inter->refInter->getLevelString()), 6, 1); + + this->setLayout(layout); + + show(); +} diff --git a/InterfacePropertiesWindow.h b/InterfacePropertiesWindow.h new file mode 100644 index 0000000..3b372a9 --- /dev/null +++ b/InterfacePropertiesWindow.h @@ -0,0 +1,22 @@ +#ifndef __INTERFACEPROPERTIESWINDOW_H__ +#define __INTERFACEPROPERTIESWINDOW_H__ + +#include + +#include "InterfaceItem.h" + +class InterfacePropertiesWindow : public QWidget +{ + Q_OBJECT +public: + explicit InterfacePropertiesWindow(InterfaceItem *_inter, QWidget *parent = 0); + +private: + QGridLayout *layout; + InterfaceItem *inter; + + + +}; + +#endif // INTERFACEPROPERTIESWINDOW_H diff --git a/MainWindow.cpp b/MainWindow.cpp new file mode 100644 index 0000000..01c23c1 --- /dev/null +++ b/MainWindow.cpp @@ -0,0 +1,399 @@ +#include "MainWindow.h" +#include "Dispatcher.h" +#include "Parameters.h" +#include "BlockLibraryWidget.h" +#include "GroupWidget.h" +#include "GroupScene.h" +#include "BlockWidget.h" +#include "AbstractBoxItem.h" +#include "Graph.h" +#include "GroupItem.h" +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + + versionMaj = VERSION_MAJ; + versionMin = VERSION_MIN; + revision = REVISION; + + // reading parameters + params = new Parameters(); + try { + params->loadBlastConfiguration("blastconfig.xml"); + + if (!QFileInfo::exists(params->refLib)) { + params->loadReferencesFromXml(); + int ret = QMessageBox::question(this,tr("Building references library"),tr("The reference block library does not exists.\n References have been read directly from the xml descriptions of blocks.\n It can be saved into a library in order to start application faster. "), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + if (ret == QMessageBox::Ok) { + params->saveReferencesToLib(); + } + } + else { + params->loadReferencesFromLib(); + } + + if (!QFileInfo::exists(params->implLib)) { + params->loadImplementationsFromXml(); + int ret = QMessageBox::question(this,tr("Building implementations library"),tr("The block implementations library does not exists.\nImplementations have been read directly from the xml descriptions.\n It can be saved into a library in order to start application faster. "), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + if (ret == QMessageBox::Ok) { + params->saveImplementationsToLib(); + } + } + else { + params->loadImplementationsFromLib(); + } + } + catch(Exception err) { + cerr << qPrintable(err.getDefaultMessage()) << endl; + cerr << "Aborting ..." << endl; + exit(1); + } + + cout << "all references and implementations are loaded" << endl; + + // create the menu, action, ... + dispatcher = new Dispatcher(params,this); + params->setDispatcher(dispatcher); + + // creating block library + library = new BlockLibraryWidget(dispatcher,params); + isCurrentProject = false; + + QLabel* labDefault = new QLabel("BLAST: BLock ASsembler Tool"); + stackedWidget = new QStackedWidget; + stackedWidget->addWidget(labDefault); + stackedWidget->setCurrentIndex(0); + this->setCentralWidget(stackedWidget); + this->setMinimumSize(800,600); + + createActions(); + createMenus(); + setWindowTitle("blast - top group"); + setFocusPolicy(Qt::StrongFocus); + setFocus(); + + readSettings(); + + initialize(); + +} + +MainWindow::~MainWindow() {} + +void MainWindow::initialize() { + + projectMenuEnb = 0; + + stackedWidget->setCurrentIndex(0); + enableProjectActions(true,PROJECT_NEW | PROJECT_OPEN, OP_RAZ); + + stackedWidget->setCurrentIndex(0); + + resize(500,300); +} + +void MainWindow::readSettings() { + QSettings settings; + settings.beginGroup("init"); + checkNewVersion = settings.value("check_new_version").toString(); + settings.endGroup(); + if (checkNewVersion.isEmpty()) { + checkNewVersion = "true"; + } + /* + cout << "test nouvelle version : " << qPrintable(checkNewVersion) << endl; + QUrl url("http://www.hrafnheim.fr/download/Cartomagic/carto_currentversion.txt"); + QNetworkRequest request(url); + manager = new QNetworkAccessManager(this); + connect(manager,SIGNAL(finished(QNetworkReply*)), this, SLOT(slotCheckNewVersion(QNetworkReply*))); + manager->get(request); + */ +} + +void MainWindow::writeSettings() { + QSettings settings; + settings.beginGroup("init"); + settings.setValue("check_new_version",checkNewVersion); + settings.endGroup(); +} + +void MainWindow::slotCheckNewVersion(QNetworkReply *reply) { + + if (reply->error() == QNetworkReply::NoError) { + QString txt = reply->readAll(); + QString currentVer = QString("%1.%2.%3").arg(versionMaj).arg(versionMin).arg(revision); + if (txt.contains(currentVer)) { + cout << "a jour" << endl; + } + else { + cout << "dernière version : " << qPrintable(txt) << ", version actuelle = " << qPrintable(currentVer) << endl; + } + } + else { + cout << "erreur = " << qPrintable(reply->errorString()) << endl; + } + reply->deleteLater(); +} + +void MainWindow::enableProjectActions(bool enbMenu, quint16 mask, quint8 op) { + if (enbMenu) { + projectMenu->setEnabled(true); + } + else { + projectMenu->setEnabled(false); + } + + if (op == OP_ADD) { + projectMenuEnb = projectMenuEnb | mask; + } + else if (op == OP_REM) { + projectMenuEnb = (projectMenuEnb | mask) ^ mask; + } + else if (op == OP_RAZ) { + projectMenuEnb = mask; + } + + + if (projectMenuEnb & PROJECT_NEW) { + newProject->setEnabled(true); + } + else { + newProject->setEnabled(false); + } + if (projectMenuEnb & PROJECT_OPEN) { + openProject->setEnabled(true); + } + else { + openProject->setEnabled(false); + } + if (projectMenuEnb & PROJECT_SAVE) { + saveProject->setEnabled(true); + } + else { + saveProject->setEnabled(false); + } + if (projectMenuEnb & PROJECT_SAVEAS) { + saveAsProject->setEnabled(true); + } + else { + saveAsProject->setEnabled(false); + } + if (projectMenuEnb & PROJECT_CLOSE) { + closeProject->setEnabled(true); + } + else { + closeProject->setEnabled(false); + } + if (projectMenuEnb & PROJECT_LIB) { + openLibrary->setEnabled(true); + } + else { + openLibrary->setEnabled(false); + } +} + +void MainWindow::createMenus(){ + + allMenuBar = menuBar(); + + projectMenu = allMenuBar->addMenu(tr("&Project")); + toolsMenu = allMenuBar->addMenu(tr("&Tools")); + + projectMenu->addAction(newProject); + projectMenu->addAction(openProject); + projectMenu->addAction(saveProject); + projectMenu->addAction(saveAsProject); + projectMenu->addAction(closeProject); + projectMenu->addAction(openLibrary); + + toolsMenu->addAction(newBlockWidgetAct); + toolsMenu->addAction(graphValidation); + +} + +void MainWindow::createActions() { + + newProject = new QAction(tr("&New project"), this); + newProject->setIcon(QPixmap::fromImage(QImage("icons/new.ico"))); + newProject->setStatusTip(tr("Create a new project")); + connect(newProject, SIGNAL(triggered()), this, SLOT(slotNewProject())); + + openProject = new QAction(tr("&Open project"), this); + openProject->setIcon(QPixmap::fromImage(QImage("icons/load.png"))); + openProject->setStatusTip(tr("Open an existing project")); + connect(openProject, SIGNAL(triggered()), this, SLOT(slotLoadProject())); + + saveProject = new QAction(tr("&Save project"), this); + saveProject->setIcon(QPixmap::fromImage(QImage("icons/save.png"))); + saveProject->setStatusTip(tr("Save the current project")); + connect(saveProject, SIGNAL(triggered()), this, SLOT(slotSaveProject())); + + saveAsProject = new QAction(tr("&Save project as..."), this); + saveAsProject->setIcon(QPixmap::fromImage(QImage("icons/save-as.png"))); + saveAsProject->setStatusTip(tr("Save the current project as...")); + connect(saveAsProject, SIGNAL(triggered()), this, SLOT(slotSaveAsProject())); + + closeProject = new QAction(tr("&Close project"), this); + closeProject->setIcon(QPixmap::fromImage(QImage("icons/close.png"))); + closeProject->setStatusTip(tr("Close the current project")); + connect(closeProject, SIGNAL(triggered()), this, SLOT(slotCloseProject())); + + openLibrary = new QAction(tr("Open block &Library"), this); + openLibrary->setIcon(QPixmap::fromImage(QImage("icons/add_block.png"))); + openLibrary->setStatusTip(tr("Open block library window")); + connect(openLibrary, SIGNAL(triggered()), this, SLOT(slotOpenBlockLibrary())); + + newBlockWidgetAct = new QAction(tr("&XML generator"), this); + newBlockWidgetAct->setIcon(QPixmap::fromImage(QImage("icons/new.ico"))); + newBlockWidgetAct->setStatusTip(tr("Create a new XML generator")); + connect(newBlockWidgetAct, SIGNAL(triggered()), this, SLOT(slotNewBlockWidget())); + + graphValidation = new QAction(tr("&graph validation"), this); + graphValidation->setIcon(QPixmap::fromImage(QImage("icons/new.ico"))); + graphValidation->setStatusTip(tr("validate the graph")); + connect(graphValidation, SIGNAL(triggered()), this, SLOT(slotGraphValidation())); + +} + +void MainWindow::save(QString absoluteFilename) { + params->save(absoluteFilename); +} + +void MainWindow::slotLoadProject(){ + + absoluteFilename = QFileDialog::getOpenFileName(0, "select a project file", "save/",tr("sauvegardes (*.xml)")); + + if(! absoluteFilename.isEmpty()){ + GroupWidget* topGroup = dispatcher->loadProject(absoluteFilename); + if (topGroup != NULL) { + addTopGroup(topGroup); + } + else { + QMessageBox msgBox; + msgBox.setText("Cannot open the project."); + msgBox.setInformativeText("Do you want to save your changes?"); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + + int ret = msgBox.exec(); + } + } +} + + +void MainWindow::slotNewProject(){ + + enableProjectActions(true, PROJECT_CLOSE | PROJECT_SAVE | PROJECT_SAVEAS | PROJECT_LIB, OP_RAZ); + GroupWidget* topGroup = dispatcher->createTopScene(); + addTopGroup(topGroup); + +} + +void MainWindow::slotCloseProject(){ + + // removing the GroupWidget from stack + QWidget *widget = stackedWidget->widget(1); + stackedWidget->removeWidget(widget); + stackedWidget->setCurrentIndex(0); + + dispatcher->closeCurrentProject(); + + + isCurrentProject = false; + params->unsaveModif = false; + absoluteFilename = QString(); + + initialize(); +} + + +void MainWindow::slotNewBlockWidget() { + new BlockWidget(); +} + +void MainWindow::slotSaveProject(){ + if(absoluteFilename != QString()){ + save(absoluteFilename); + } else { + slotSaveAsProject(); + } +} + +void MainWindow::slotSaveAsProject(){ + if(isCurrentProject){ + QFileDialog dial(0, "Select a file", "save/"); + dial.setDefaultSuffix(".xml"); + dial.setAcceptMode(QFileDialog::AcceptSave); + if(dial.exec() == QFileDialog::AcceptSave){ + absoluteFilename = dial.selectedFiles().at(0); + if(absoluteFilename != QString()) + save(absoluteFilename); + } + } +} + +void MainWindow::slotOpenBlockLibrary() { + dispatcher->showBlocksLibrary(); +} + + +void MainWindow::slotGraphValidation() { + params->parametersValidation(); +} + +void MainWindow::addTopGroup(GroupWidget *_topGroup) { + topGroup = _topGroup; + stackedWidget->addWidget(topGroup); + stackedWidget->setCurrentIndex(1); +} + +void MainWindow::removeTopGroup() { + stackedWidget->removeWidget(topGroup); + topGroup->deleteLater(); + stackedWidget->setCurrentIndex(0); +} + +void MainWindow::closeEvent(QCloseEvent *event){ + if(isCurrentProject){ + QMessageBox msgBox; + msgBox.setText("The project has been modified."); + msgBox.setInformativeText("Do you want to save your changes?"); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + + int ret = msgBox.exec(); + + switch(ret) { + case QMessageBox::Save : + slotSaveProject(); + slotCloseProject(); + break; + case QMessageBox::Discard : + slotCloseProject(); + break; + } + event->ignore(); + } else { + exit(0); + } +} + +void MainWindow::mousePressEvent(QMouseEvent *e) { + + if (dispatcher->getCurrentGroup() != NULL) { + dispatcher->setCurrentGroupWidget(dispatcher->getCurrentGroup()); + } + QMainWindow::mousePressEvent(e); +} + +void MainWindow::focusInEvent(QFocusEvent *e) { +/* + if(params->currentWindow != this){ + params->setCurrentWindow(this); + changeConnectionMode(false); + } + */ +} diff --git a/MainWindow.h b/MainWindow.h new file mode 100644 index 0000000..ee51e4c --- /dev/null +++ b/MainWindow.h @@ -0,0 +1,128 @@ +#ifndef __MAINWINDOW_H__ +#define __MAINWINDOW_H__ + +#include + +#include +#include +#include +#include + +class Dispatcher; +class Parameters; +class BlockLibraryWidget; +class GroupWidget; +class BlockWidget; +class Graph; + +// versioning related +#define MAGIC_STRING "opentrace" +#define VERSION_MAJ (quint8)0 // major version code +#define VERSION_MIN (quint8)2 // minor version number +#define REVISION (quint8)1 // revision number of current version + + +// defines for menus +#define TRACE_MENU (quint8)1 + +// defines for actions +#define NONE_ACT (quint16)0 + +#define PROJECT_NEW (quint16)1 +#define PROJECT_OPEN (quint16)2 +#define PROJECT_SAVE (quint16)4 +#define PROJECT_SAVEAS (quint16)8 +#define PROJECT_CLOSE (quint16)16 +#define PROJECT_LIB (quint16)32 + +#define OP_ADD (quint8)0 +#define OP_REM (quint8)1 +#define OP_RAZ (quint8)2 + +using namespace std; +using namespace Qt; + + +class MainWindow : public QMainWindow { + + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + void initialize(); + + void addTopGroup(GroupWidget* _topGroup); + void removeTopGroup(); // called when closing project + + + inline BlockLibraryWidget *getLibrary(){return library;} + + +protected: + void closeEvent(QCloseEvent *); + void mousePressEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *e); + +private: + + GroupWidget* topGroup; + QStackedWidget *stackedWidget; + Dispatcher *dispatcher; + Parameters *params; + BlockLibraryWidget *library; + + bool isCurrentProject; + QString absoluteFilename; + + QString checkNewVersion; + + void save(QString absoluteFilename); + + void createActions(); + void createMenus(); + + void readSettings(); + void writeSettings(); + + /* Menus */ + QMenuBar *allMenuBar; + + QMenu* projectMenu; + quint16 projectMenuEnb; + QMenu* toolsMenu; + + QAction* newProject; + QAction* openProject; + QAction* saveProject; + QAction* saveAsProject; + QAction* closeProject; + QAction* openLibrary; + + QAction *newBlockWidgetAct; + QAction *graphValidation; + + + // versioning related + quint8 versionMaj; + quint8 versionMin; + quint8 revision; + +public slots: + void enableProjectActions(bool enbMenu, quint16 mask = 0, quint8 op = 0); // default : add nothing + +private slots: + void slotNewProject(); + void slotLoadProject(); + void slotSaveProject(); + void slotSaveAsProject(); + void slotCloseProject(); + void slotOpenBlockLibrary(); + + void slotNewBlockWidget(); + void slotGraphValidation(); + + void slotCheckNewVersion(QNetworkReply *reply); +}; + +#endif // MAINWINDOW_H diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..e18672c --- /dev/null +++ b/Makefile.in @@ -0,0 +1,185 @@ +############################################################################# +# Makefile for building: @@APPNAME@@ +############################################################################# + +####### VERSION (modified by the configure script) ############ +APPNAME=@@APPNAME@@ + +####### VERSION (modified by the configure script) ############ +VERSION=@@APPVER@@ + +####### OS (modified by the configure script) ############ +OS=@@OS@@ +ARCH=@@ARCH@@ + +####### Qt (modified by the configure script) ############ +QTVER=@@QTVER@@ +QTPATH=@@QTPATH@@ + +####### PATHES ############ +BUILDDIR=build +DISTDIR=dist +BUILDPATH=$(BUILDDIR)/$(OS)$(ARCH) +DISTPATH=$(DISTDIR)/$(OS)$(ARCH)/$(APPNAME)-$(VERSION) +ARDIR=archive +ARPATH=$(ARDIR)/$(APPNAME)/v$(VERSION) + +####### COMPILERS ############ +CC-lin32 = gcc +CXX-lin32 = g++ +CC-lin64 = gcc +CXX-lin64 = g++ +CC-win32 = i686-w64-mingw32-gcc-win32 +CXX-win32 = i686-w64-mingw32-g++-win32 +WINDRES-win32 = i686-w64-mingw32-windres +CC-win64 = x86_64-w64-mingw32-gcc-win32 +CXX-win64 = x86_64-w64-mingw32-g++-win32 +WINDRES-win64 = x86_64-w64-mingw32-windres + +CC = $(CC-$(OS)$(ARCH)) +CXX = $(CXX-$(OS)$(ARCH)) +WINDRES = $(WINDRES-$(OS)$(ARCH)) + +DEFINES-lin32 = -DDEBUG -DQT_NO_DEBUG -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -D@@APPDEF@@_LIN +DEFINES-lin64 = -DDEBUG -DQT_NO_DEBUG -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -D@@APPDEF@@_LIN +DEFINES-win32 = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN -DQT_AXCONTAINER_LIB -DQT_PRINTSUPPORT_LIB -DQT_AXBASE_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_XML_LIB -D@@APPDEF@@_WIN + +DEFINES = $(DEFINES-$(OS)$(ARCH)) + +CFLAGS-lin32 = @@DEBUG@@ -pipe -O2 -Wall -fPIC -D_REENTRANT $(DEFINES) +CFLAGS-lin64 = @@DEBUG@@ -pipe -O2 -Wall -fPIC -D_REENTRANT $(DEFINES) +CXXFLAGS-lin32 = @@DEBUG@@ -pipe -O2 -Wall -fPIC -D_REENTRANT $(DEFINES) +CXXFLAGS-lin64 = @@DEBUG@@ -pipe -O2 -Wall -fPIC -D_REENTRANT $(DEFINES) +CFLAGS-win32 = @@DEBUG@@ -pipe -fno-keep-inline-dllexport -O2 -Wall -Wextra $(DEFINES) +CXXFLAGS-win32 = @@DEBUG@@ -pipe -fno-keep-inline-dllexport -O2 -frtti -Wall -Wextra -fexceptions -mthreads $(DEFINES) + +CFLAGS = $(CFLAGS-$(OS)$(ARCH)) +CXXFLAGS = $(CXXFLAGS-$(OS)$(ARCH)) + +INCPATH-lin64-qt4 = -I/usr/share/qt4/mkspecs/linux-g++ -I$(QTPATH)/QtCore -I$(QTPATH)/QtGui -I$(QTPATH)/QtNetwork -I$(QTPATH)/QtXml -I$(QTPATH)/QtXmlPatterns -I$(QTPATH) +INCPATH-lin64-qt5 = -I$(QTPATH)/mkspecs/linux-g++-64 -I$(QTPATH) -I$(QTPATH)/QtWidgets -I$(QTPATH)/QtCore -I$(QTPATH)/QtGui -I$(QTPATH)/QtPrintSupport -I$(QTPATH)/QtNetwork -I$(QTPATH)/QtXml -I$(QTPATH)/QtXmlPatterns +INCPATH-win32-qt5 = -I$(QTPATH)/mkspecs/win32-g++ -I$(QTPATH)/include -I$(QTPATH)/include/ActiveQt -I$(QTPATH)/include/QtWidgets -I$(QTPATH)/include/QtGui -I$(QTPATH)/include/QtCore -I$(QTPATH)/include/QtXml -I$(QTPATH)/include/QtXmlPatterns -I$(QTPATH)/include/QtPrintSupport + +INCPATH = $(INCPATH-$(OS)$(ARCH)-qt$(QTVER)) -I. + +################## LINKER ##################### +LINK-lin32 = g++ +LINK-lin64 = g++ +LINK-win32 = i686-w64-mingw32-g++-win32 +LINK-win64 = x86_64-w64-mingw32-g++-win32 + +LINK = $(LINK-$(OS)$(ARCH)) + +LFLAGS-lin32 = -m32 -Wl,-O1 +LFLAGS-lin64 = -m64 -Wl,-O1 +LFLAGS-win32 = -Wl,-s -mthreads -Wl,-subsystem,console -mthreads -static-libgcc -static-libstdc++ +LFLAGS-win64 = -Wl,-s -mthreads -Wl,-subsystem,console -mthreads -static-libgcc -static-libstdc++ + +LFLAGS = $(LFLAGS-$(OS)$(ARCH)) + +LIBS-lin64-qt4 = -lQtCore -lQtGui -lQtXml -lQtXmlPatterns -lpthread -lm +LIBS-lin64-qt5 = -lQt5Core -lQt5Gui -lQt5Xml -lQt5XmlPatterns -lQt5Widgets -lQt5PrintSupport -lQt5Network -lpthread -lm +LIBS-win32-qt5 = -lmingw32 -L$(QTPATH)/lib -lqtmain -lQt5AxContainer -lQt5PrintSupport -lQt5AxBase -lglu32 -lopengl32 -lole32 -loleaut32 -luser32 -lgdi32 -ladvapi32 -luuid -lQt5Widgets -lQt5Gui -lQt5Core -lQt5Xml -lQt5XmlPatterns -lQt5Network -lm -lws2_32 + +LIBS = $(LIBS-$(OS)$(ARCH)-qt$(QTVER)) + +################## OBJECTS ##################### +include object-files.txt + +OBJ-lin = $(COMMON-OBJ) +OBJ-win = $(COMMON-OBJ) $(BUILDPATH)/$(APPNAME)_res.o + +OBJ = $(OBJ-$(OS)) + +################## EXECUTBALE #################### +EXENAME-lin = $(APPNAME) +EXENAME-win = $(APPNAME).exe + +EXENAME = $(EXENAME-$(OS)) + +all: $(BUILDPATH)/$(EXENAME) + +$(BUILDPATH)/$(EXENAME) : $(OBJ) + $(LINK) $(LFLAGS) -o $@ $^ $(LIBS) + cp $(BUILDPATH)/$(EXENAME) . + +$(BUILDPATH)/$(APPNAME)_res.o: $(APPNAME).rc + $(WINDRES) -i $(APPNAME).rc -o $(BUILDPATH)/$(APPNAME)_res.o --include-dir=. $(DEFINES) + +################## DISTRIBUTION ARCHIVE ##################### +DISTNAME = dist-$(OS) + +dist : $(DISTNAME) + +dist-lin: $(BUILDPATH)/$(APPNAME) + @echo -n creating binary distribution archive for Linux ... + @-rm -rf $(DISTPATH) + @-mkdir -p $(DISTPATH) + @-mkdir -p $(DISTPATH)/locales + @cp $(BUILDPATH)/$(APPNAME) $(DISTPATH) + @if ls $(APPNAME)_*.qm 2>/dev/null 1>&2; then for loc in $(APPNAME)_*.qm; do cp $$loc $(DISTPATH)/locales; done; fi + @cp install.sh $(DISTPATH) + @if [ -d examples ]; then cp -r examples $(DISTPATH); fi + @cd $(DISTPATH); cd ..; tar zcf $(APPNAME)-$(VERSION)_$(OS)$(ARCH).tgz $(APPNAME)-$(VERSION); rm -rf $(APPNAME)-$(VERSION) + @echo done; echo result is in $(DISTDIR)/$(OS)$(ARCH)/$(APPNAME)-$(VERSION)_$(OS)$(ARCH).tgz + +dist-win: $(BUILDPATH)/$(EXENAME) + @echo -n creating binary distribution archive for Windows ... + @rm -rf $(DISTPATH) + @mkdir -p $(DISTPATH) + @cp $(BUILDPATH)/$(APPNAME).exe $(DISTPATH) + @cp -r lib/$(OS)$(ARCH)/* $(DISTPATH) + @if ls $(APPNAME)_*.qm 2>/dev/null 1>&2; then for loc in $(APPNAME)_*.qm; do cp $$loc $(DISTPATH); done; fi + @if [ -d examples ]; then cp -r examples $(DISTPATH); fi + @cd $(DISTPATH); cd ..; zip -r $(APPNAME)-$(VERSION)_$(OS)$(ARCH).zip $(APPNAME)-$(VERSION)/* ; rm -rf $(APPNAME)-$(VERSION) + @echo done; echo result is in $(DISTDIR)/$(OS)$(ARCH)/$(APPNAME)-$(VERSION)_$(OS)$(ARCH).zip + +src-dist: + @echo -n creating source archive ... + @rm -rf $(ARPATH) + @mkdir -p $(ARPATH) + @cp *.cpp $(ARPATH) + @cp *.h $(ARPATH) +# copying various files: translations (.ts), locales (.qm), resources (.qrc), xml related (.xml,.xsd), config. files (.conf) ... + @if ls $(APPNAME)_*.ts 2>/dev/null 1>&2; then for loc in $(APPNAME)_*.ts; do cp $$loc $(ARPATH); done; fi + @if ls $(APPNAME)_*.qm 2>/dev/null 1>&2; then for loc in $(APPNAME)_*.qm; do cp $$loc $(ARPATH); done; fi + @if ls *.conf 2>/dev/null 1>&2; then for loc in *.conf; do cp $$loc $(ARPATH); done; fi + @if ls *.xml 2>/dev/null 1>&2; then for loc in *.xml; do cp $$loc $(ARPATH); done; fi + @if ls *.xsd 2>/dev/null 1>&2; then for loc in *.xsd; do cp $$loc $(ARPATH); done; fi + @if [ -f $(APPNAME).qrc ]; then cp $(APPNAME).qrc $(ARPATH); fi + @if [ -d icons ]; then cp -r icons $(ARPATH); fi + @if [ -d examples ]; then cp -r examples $(ARPATH); fi + @cp -r lib $(ARPATH) + @cp install.sh.in $(ARPATH) + @cp Makefile.in $(ARPATH) + @cp object-files.txt $(ARPATH) + @cp configure $(ARPATH) + @if [ -f $(APPNAME).rc ]; then cp $(APPNAME).rc $(ARPATH); fi + @if [ -f $(APPNAME).ico ]; then cp $(APPNAME).ico $(ARPATH); fi + @cp $(APPNAME).creator $(ARPATH) + @if [ -f $(APPNAME).creator.user ]; then cp $(APPNAME).creator.user $(ARPATH); fi + @cp $(APPNAME).files $(ARPATH) + @cp $(APPNAME).includes $(ARPATH) + @if [ -f $(APPNAME).config ]; then cp $(APPNAME).config $(ARPATH); fi + @cd $(ARPATH); cd ../..; tar zcf $(APPNAME)-$(VERSION)-src.tgz $(APPNAME); rm -rf $(APPNAME) + @echo done; echo result is in $(ARDIR)/$(APPNAME)-$(VERSION)-src.zip +clean: + rm -f $(OBJ) + rm -f *~ + rm -f moc_*.cpp + rm -f rcc_*.cpp + rm -f $(BUILDPATH)/$(EXENAME) + rm -f $(EXENAME) + +### NEW RULES ### +$(BUILDPATH)/%.o : %.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +moc_%.cpp : %.h + moc -qt=$(QTVER) $(DEFINES) $(INCPATH) $< -o $@ + +rcc_%.cpp : %.qrc + rcc -qt=$(QTVER) $< -o $@ -name $* + +### DEPENDENCIES OF EACH SOURCE FILE (auto-added by configure) ### + diff --git a/Parameters.cpp b/Parameters.cpp new file mode 100644 index 0000000..c991e5f --- /dev/null +++ b/Parameters.cpp @@ -0,0 +1,1220 @@ +#include "Parameters.h" + +#include "Dispatcher.h" +#include "BlockLibraryTree.h" + +#include "BlockCategory.h" + +#include "GroupWidget.h" +#include "GroupScene.h" +#include "GroupItem.h" +#include "BoxItem.h" +#include "InterfaceItem.h" +#include "ConnectionItem.h" + +#include "Graph.h" +#include "ReferenceBlock.h" +#include "GroupBlock.h" +#include "FunctionalBlock.h" +#include "ReferenceInterface.h" +#include "GroupInterface.h" +#include "FunctionalInterface.h" + +#include "Exception.h" +#include "BlocksToConfigureWidget.h" + +Parameters::Parameters() { + categoryTree = NULL; + arrowWidth = 5; + arrowHeight = 10; + arrowLineLength = 10; + + defaultBlockWidth = 100; + defaultBlockHeight = 100; + defaultBlockFont = QFont("Arial"); + defaultBlockFontSize = 12; + + setArrowPathes(); + + sceneMode = MODE_EDITION; // default mode + editState = Parameters::EditNoOperation; + + unsaveModif = false; + isRstClkShown = false; + + projectPath = QDir::currentPath(); +} + +Parameters::~Parameters() { + clear(); +} + +void Parameters::clear() { + delete categoryTree; + QListIterator iter(availableBlocks); + while(iter.hasNext()) { + ReferenceBlock* item = iter.next(); + delete item; + } + availableBlocks.clear(); + refPathes.clear(); +} + +Graph* Parameters::createGraph() { + graph = new Graph(); + return graph; +} + +void Parameters::destroyGraph() { + delete graph; +} + +GroupBlock* Parameters::addGroupBlock() { + GroupBlock* parent = AB_TO_GRP(currentScene->getGroupItem()->getRefBlock()); + GroupBlock* newOne = graph->createChildBlock(parent); + return newOne; +} + +FunctionalBlock* Parameters::addFunctionalBlock(int idCategory, int idBlock) { + + BlockCategory* blockCat = categoryTree->searchCategory(idCategory); + + if (blockCat == NULL) return NULL; + GroupBlock* group = AB_TO_GRP(currentScene->getGroupItem()->getRefBlock()); + ReferenceBlock* ref = blockCat->getBlock(idBlock); + if (ref == NULL) return NULL; + + FunctionalBlock* newOne = graph->addFunctionalBlock(group, ref); + unsaveModif = true; + + return newOne; +} + +FunctionalBlock* Parameters::duplicateFunctionalBlock(FunctionalBlock *block) { + + ReferenceBlock* ref = block->getReference(); + GroupBlock* group = AB_TO_GRP(block->getParent()); + + // adding to the group + FunctionalBlock* newBlock = new FunctionalBlock(group,ref); + newBlock->populate(); + group->addBlock(newBlock); + + return newBlock; +} + +void Parameters::validateXmlFile(const QString& xmlFileName, const QString& xsdFileName, XmlFileType fileType) throw(Exception) { + // opening configFile + QFile xmlFile(xmlFileName); + if (!xmlFile.open(QIODevice::ReadOnly)) { + if (fileType == Configuration) { + throw(Exception(CONFIGFILE_NOACCESS)); + } + else if (fileType == Reference) { + throw(Exception(BLOCKFILE_NOACCESS)); + } + else if (fileType == Implementation) { + throw(Exception(IMPLFILE_NOACCESS)); + } + else if (fileType == Project) { + throw(Exception(PROJECTFILE_NOACCESS)); + } + } + + QFile xsdFile(xsdFileName); + if (!xsdFile.open(QIODevice::ReadOnly)) { + xsdFile.close(); + if (fileType == Configuration) { + throw(Exception(CONFIGFILE_NOACCESS)); + } + else if (fileType == Reference) { + throw(Exception(BLOCKFILE_NOACCESS)); + } + else if (fileType == Implementation) { + throw(Exception(IMPLFILE_NOACCESS)); + } + else if (fileType == Project) { + throw(Exception(PROJECTFILE_NOACCESS)); + } + } + + if(validate(xmlFile,xsdFile) == false) { + xmlFile.close(); + xsdFile.close(); + if (fileType == Configuration) { + throw(Exception(CONFIGFILE_CORRUPTED)); + } + else if (fileType == Reference) { + throw(Exception(BLOCKFILE_CORRUPTED)); + } + else if (fileType == Implementation) { + throw(Exception(IMPLFILE_CORRUPTED)); + } + else if (fileType == Project) { + throw(Exception(PROJECTFILE_CORRUPTED)); + } + } + xmlFile.close(); + xsdFile.close(); +} + +bool Parameters::validate(QFile& fileXml, QFile& fileSchema) { + + // 2 files are supposed to be already opened + QXmlSchema schema; + + if(! schema.load(&fileSchema)){ + cout << "invalid schema" << endl; + return false; + } + + QXmlSchemaValidator validator(schema); + + if(! validator.validate(&fileXml)){ + cout << "invalid xml" << endl; + return false; + } + return true; +} + +QDomElement Parameters::openProjectFile(const QString& projectFileName) throw(Exception) { + + try { + validateXmlFile(projectFileName,"projectfile.xsd",Project); + } + catch(Exception err) { + throw(err); + } + + QFile projectFile(projectFileName); + QDomDocument doc("projectFile"); + + if(!projectFile.open(QIODevice::ReadOnly)) { + throw(Exception(PROJECTFILE_NOACCESS)); + } + if(!doc.setContent(&projectFile)) { + projectFile.close(); + throw(Exception(PROJECTFILE_CORRUPTED)); + } + projectFile.close(); + + QDomElement root = doc.documentElement(); + + return root; +} + +void Parameters::loadProject(QDomElement root) { + +#ifdef DEBUG_INCLFUN + + bool ok = false; + GroupWidget* groupWidget = NULL; + GroupItem *groupItem = NULL; + GroupBlock *groupBlock = NULL; + + /********************************************************** + 1 : getting scene and creating associated group widgets + ***********************************************************/ + QDomNodeList scenesNodes = root.elementsByTagName("scene"); + + for(int i=0; icreateTopScene(); + topScene->setId(idScene); + groupItem = topScene->getGroupItem(); + groupBlock = AB_TO_GRP(groupItem->getRefBlock()); + cout << "top group added to scene n°" << idScene << endl; + } + else { + GroupScene* scene = searchSceneById(idUpperScene, topScene); + GroupWidget* parent = scene->getGroupWindow(); + groupWidget = dispatcher->createChildScene(parent); + groupItem = groupWidget->getScene()->getGroupItem(); + groupBlock = AB_TO_GRP(groupItem->getRefBlock()); + } + /********************************************************** + 1.1 : getting the group item + ***********************************************************/ + QDomElement groupItemNode = currentSceneNode.firstChildElement("group_item"); + + int id = groupItemNode.attribute("id","none").toInt(&ok); + if(!ok) throw(Exception(PROJECTFILE_CORRUPTED)); + + QString name = groupItemNode.attribute("name","none"); + if(name == "none") throw(Exception(PROJECTFILE_CORRUPTED)); + + QStringList positionStr = groupItemNode.attribute("position","none").split(","); + if(positionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED)); + int posX = positionStr.at(0).toInt(&ok); + if(!ok) throw(Exception(PROJECTFILE_CORRUPTED)); + int posY = positionStr.at(1).toInt(&ok); + if(!ok) throw(Exception(PROJECTFILE_CORRUPTED)); + + QStringList dimensionStr = groupItemNode.attribute("dimension","none").split(","); + if(dimensionStr.length() != 2) throw(Exception(PROJECTFILE_CORRUPTED)); + int dimX = dimensionStr.at(0).toInt(&ok); + if(!ok) throw(Exception(PROJECTFILE_CORRUPTED)); + int dimY = dimensionStr.at(1).toInt(&ok); + if(!ok) throw(Exception(PROJECTFILE_CORRUPTED)); + + groupItem->setId(id); + groupItem->setPos(posX,posY); + groupItem->setDimension(dimX,dimY); + groupBlock->setName(name); + + if (idUpperScene != -1) { + groupWidget->setWindowTitle(groupBlock->getName()); + groupWidget->show(); + } + cout << "group info : \n-id : " << id << "\n-pos : " << posX << ", " << posY << "\n-dim : " << dimX << ", " << dimY << "\n-name : " << name.toStdString() << endl; + + QDomNodeList interfaces = groupItemNode.elementsByTagName("group_iface"); + for(int j=0; jsetId(id); + + groupBlock->addInterface(groupInterface); + groupItem->addInterface(interfaceItem); + cout << "interface add to " << groupBlock->getName().toStdString() << endl; + } + } + + cout << "groupItems loaded and windows created succefully!" << endl; + + + for(int i=0; igetGroupItem()->getRefBlock(),reference); + functionalBlock->setName(name); + + ((GroupBlock*)currentScene->getGroupItem()->getRefBlock())->addBlock(functionalBlock); + + + BlockItem *blockItem = new BlockItem(currentScene->getGroupItem(),functionalBlock,dispatcher,this); + blockItem->setPos(posX,posY); + blockItem->setDimension(dimX,dimY); + blockItem->setId(id); + ((GroupItem*)currentScene->getGroupItem())->addBlockItem(blockItem); + currentScene->addItem(blockItem); + currentScene->addBlockItem(blockItem); + + QDomNodeList blockParamNodes = currentFBNode.elementsByTagName("bif_parameter"); + + for(int i=0; isetName(name); + blockParam->setValue(value); + blockParam->setType(type); + if(context == "constant") blockParam->setContext(BlockParameter::Constant); + if(context == "user") blockParam->setContext(BlockParameter::User); + if(context == "generic") blockParam->setContext(BlockParameter::Generic); + if(context == "wb") blockParam->setContext(BlockParameter::Wishbone); + if(context == "port") blockParam->setContext(BlockParameter::Port); + + functionalBlock->addParameter(blockParam); + } + + + QDomNodeList interfaceNodes = currentFBNode.elementsByTagName("bif_iface"); + + for(int i=0; igetIfaceFromName(refName); + FunctionalInterface *functionalInterface = new FunctionalInterface(functionalBlock,refInter); + functionalBlock->addInterface(functionalInterface); + functionalInterface->setName(refName); + + InterfaceItem *interfaceItem = new InterfaceItem(position,orientation,functionalInterface,blockItem,this); + interfaceItem->setId(id); + interfaceItem->setName(name); + + blockItem->addInterface(interfaceItem); + + } + } + } + cout << "functionalBlocks loaded and created succefully!" << endl; + + + for(int i=0; igetRefBlock(), dispatcher, this); + blockItem->setChildGroupItem(insideGroup); + blockItem->setId(id); + blockItem->setPos(posX,posY); + blockItem->setDimension(dimX,dimY); + + ((GroupItem*)currentScene->getGroupItem())->addBlockItem(blockItem); + currentScene->addItem(blockItem); + currentScene->addBlockItem(blockItem); + + QDomNodeList interfaceNodes = currentBiGroup.elementsByTagName("big_iface"); + + for(int k=0; ksearchInterfaceByName(refName)->refInter; + InterfaceItem *ifaceItem = new InterfaceItem(position, orientation, refInter, blockItem, this); + ifaceItem->setId(id); + blockItem->addInterface(ifaceItem); + } + } + } + cout << "blockItems \"group\" loaded and created succefully!" << endl; + + + for(int i=0; isetUpperItem(upperItem); + } + } + + QDomNodeList connectionNodes = root.elementsByTagName("connection"); + + for(int i=0; iconnect(iface1,iface2); + } else { + cout << "interfaces not found, connect canceled!" << endl; + } + } + +#endif +} + +void Parameters::loadBlastConfiguration(QString confFile) throw(Exception) { + + try { + validateXmlFile("blastconfig.xml", "blastconfig.xsd",Configuration); + } + catch(Exception err) { + throw(err); + } + + bool ok; + // opening configFile + QFile configFile(confFile); + // reading in into QDomDocument + QDomDocument document("configFile"); + + if (!configFile.open(QIODevice::ReadOnly)) { + throw(Exception(CONFIGFILE_NOACCESS)); + } + if (!document.setContent(&configFile)) { + configFile.close(); + throw(Exception(CONFIGFILE_NOACCESS)); + } + configFile.close(); + + //Get the root element + QDomElement config = document.documentElement(); + + QDomElement eltCat = config.firstChildElement("categories"); + try { + categoryTree = new BlockLibraryTree(); + categoryTree->load(eltCat); + } + catch(Exception err) { + throw(err); + } + + QDomElement eltReferences = eltCat.nextSiblingElement("references"); + refLib = eltReferences.attribute("lib_file","none"); + cout << "references lib : " << qPrintable(refLib) << endl; + int nbPathes; + QString nbPathesStr; + nbPathesStr = eltReferences.attribute("nb","none"); + nbPathes = nbPathesStr.toInt(&ok); + QDomNodeList listBlockDir = eltReferences.elementsByTagName("reference_lib"); + if ((!ok) || (nbPathes != listBlockDir.size())) throw(Exception(CONFIGFILE_CORRUPTED)); + + for(int i=0;i + // for each child element, initialize the associated attributes of Parameters + + QDomElement eltDefaults = eltImpl.nextSiblingElement("defaults"); + + QDomElement eltBlocks = eltDefaults.firstChildElement("blocks"); + QString attributeStr = eltBlocks.attribute("width", "none"); + defaultBlockWidth = attributeStr.toInt(&ok); + if (!ok || defaultBlockWidth < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltBlocks.attribute("height", "none"); + defaultBlockHeight = attributeStr.toInt(&ok); + if (!ok || defaultBlockHeight < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltBlocks.attribute("font_size", "none"); + defaultBlockFontSize = attributeStr.toFloat(&ok); + if (!ok || defaultBlockFontSize < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltBlocks.attribute("font", "none"); + if (attributeStr == "none") throw(Exception(CONFIGFILE_CORRUPTED)); + defaultBlockFontName = attributeStr; + defaultBlockFont = QFont(defaultBlockFontName, defaultBlockFontSize); + + QDomElement eltInterfaces = eltBlocks.nextSiblingElement("interfaces"); + attributeStr = eltInterfaces.attribute("width", "none"); + arrowWidth = attributeStr.toInt(&ok); + if (!ok || arrowWidth < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltInterfaces.attribute("height", "none"); + arrowHeight = attributeStr.toInt(&ok); + if (!ok || arrowHeight < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltInterfaces.attribute("linelength", "none"); + arrowLineLength = attributeStr.toInt(&ok); + if (!ok || arrowLineLength < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltInterfaces.attribute("font_size", "none"); + defaultIfaceFontSize = attributeStr.toFloat(&ok); + if (!ok || defaultIfaceFontSize < 1) throw(Exception(CONFIGFILE_CORRUPTED)); + attributeStr = eltInterfaces.attribute("font", "none"); + if (attributeStr == "none") throw(Exception(CONFIGFILE_CORRUPTED)); + defaultIfaceFontName = attributeStr; + defaultIfaceFont = QFont(defaultIfaceFontName, defaultIfaceFontSize); + + QDomElement eltConnections = eltInterfaces.nextSiblingElement("connections"); + attributeStr = eltConnections.attribute("gaplength", "none"); + connGapLength = attributeStr.toInt(&ok); + if (!ok || connGapLength < 1) throw(Exception(CONFIGFILE_CORRUPTED)); +} + +void Parameters::loadReferencesFromXml() throw(Exception) { + cout << "load references from xml" << endl; + for(int i=0;i")) { + blockXML.close(); + continue; + } + + blockXML.close(); + try { + validateXmlFile(fileName,"block.xsd",Reference); + } + catch(Exception err) { + throw(err); + } + + // reading in into QDomDocument + QDomDocument document ("FileXML"); + if (!blockXML.open(QIODevice::ReadOnly)) { + throw(Exception(BLOCKFILE_NOACCESS)); + } + if (!document.setContent(&blockXML)) { + blockXML.close(); + throw(Exception(BLOCKFILE_NOACCESS)); + } + blockXML.close(); + + QDomElement blockRoot = document.documentElement(); + QString name = blockRoot.tagName(); + if (name == "block") { + + cout << "xml:" << fileName.toStdString() << endl; + ReferenceBlock* b = new ReferenceBlock(fileName); + try { + b->load(blockRoot); + b->setHashMd5(); + } + catch(int err) { + throw(err); + } + cout << "xml:" << b->getXmlFile().toStdString() << endl; + + availableBlocks.append(b); + foreach (int id,b->getCategories()) { + cout << "ajout du bloc dans cat n° : " << id << endl; + BlockCategory* cat = categoryTree->searchCategory(id); + cat->blocks.append(b); + } + } + } + } +} + +void Parameters::loadReferencesFromLib() throw(Exception) { + + cout << "loading references from lib" << endl; + + // removing blocks from category tree if they exist + categoryTree->clearBlocks(); + // deleting existings blocks + ReferenceBlock* b = NULL; + for(int i=0;i> size; + + int nbBlocks; + in >> nbBlocks; + for(int i=0;i> *b; + availableBlocks.append(b); + foreach (int id,b->getCategories()) { + BlockCategory* cat = categoryTree->searchCategory(id); + cat->blocks.append(b); + } + } + libFile.close(); +} + +void Parameters::saveReferencesToLib() throw(Exception) { + + cout << "saving blocks in " << qPrintable(refLib) << endl; + QFile libFile(refLib); + if (!libFile.open(QIODevice::WriteOnly)) { + throw(Exception(BLOCKFILE_NOACCESS)); + } + QDataStream out(&libFile); + + out.setVersion(QDataStream::Qt_5_0); + + QByteArray blockData; + QDataStream toWrite(&blockData, QIODevice::WriteOnly); + + toWrite << availableBlocks.size(); + for(int i=0;iaddImplementation(impl); + impl->setReference(ref); + cout << "OK" << endl; + } + } +} + +void Parameters::loadImplementationsFromLib() throw(Exception) { + + cout << "loading implementations from lib" << endl; + + BlockImplementation* impl = NULL; + ReferenceBlock* ref = NULL; + for(int i=0;i> size; + + int nbImpls; + in >> nbImpls; + for(int i=0;i> *impl; + availableImplementations.append(impl); + QString refMd5 = impl->getReferenceMd5(); + QString refXml = impl->getReferenceXml(); + ref = NULL; + if (! refMd5.isEmpty()) { + ref = searchBlockByMd5(refMd5); + } + if (ref == NULL) { + ref = searchBlockByXml(refXml); + } + if (ref == NULL) { + cout << "Cannot find a reference block for impl :" << qPrintable(impl->getXmlFile()) << endl; + } + ref->addImplementation(impl); + impl->setReference(ref); + } + libFile.close(); +} + +void Parameters::saveImplementationsToLib() throw(Exception) { + + cout << "saving implementations in " << qPrintable(implLib) << endl; + QFile libFile(implLib); + if (!libFile.open(QIODevice::WriteOnly)) { + throw(Exception(IMPLFILE_NOACCESS)); + } + QDataStream out(&libFile); + + out.setVersion(QDataStream::Qt_5_0); + + QByteArray blockData; + QDataStream toWrite(&blockData, QIODevice::WriteOnly); + + toWrite << availableImplementations.size(); + for(int i=0;igetCategories()) { + cout << "ajout du bloc dans cat n° : " << id << endl; + BlockCategory* cat = categoryTree->searchCategory(id); + cat->blocks.append(block); + } +} + +void Parameters::parametersValidation() { + QList blocksToConfigure = getBlocksToConfigure(); + + if(!blocksToConfigure.isEmpty()){ + BlocksToConfigureWidget *widget = new BlocksToConfigureWidget(blocksToConfigure, this, NULL); + widget->show(); + } +} + +void Parameters::connectionsValidation() { + +#ifdef DEBUG_INCLFUN + + QStack *interfaceToValidate = new QStack; + QList *validatedInterface = new QList; + + foreach(AbstractInterface *inter, topWindow->getScene()->getGroupItem()->getRefBlock()->getInterfaces()){ + foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){ + + inter->setWidth(connectedInter->getWidth()); + interfaceToValidate->push(connectedInter); + } + } + + + try{ + while(!interfaceToValidate->isEmpty()){ + interfaceToValidate->pop()->connectionsValidation(interfaceToValidate, validatedInterface); + } + } + catch(Exception e){ + cerr << e.getMessage().toStdString() << endl; + } +#endif +} + +QList Parameters::getBlocksToConfigure() { + +#ifdef DEBUG_INCLFUN + + QList *checkedBlocks = new QList; + QList *blocksToConfigure = new QList; + + foreach(AbstractInterface *inter, topWindow->getScene()->getGroupItem()->getRefBlock()->getInterfaces()){ + foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){ + if(!checkedBlocks->contains(connectedInter->getOwner())){ + connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure); + } + } + } + return *blocksToConfigure; +#endif +} + + +void Parameters::updateToolbar() { + int nb = currentScene->getBlockItems().length(); + for(int i = 0; igetBlockItems().at(i)->isSelected()){ + currentScene->getGroupWindow()->enableGroupButton(true); + return; + } + } + currentScene->getGroupWindow()->enableGroupButton(false); +} + + +void Parameters::updateIds() { + + /* a in-width cross of the graph must be done so that ids of GroupItem + are in the correct ordre when saving/loading a project + */ + int countItem = 1; + int countIface = 1; + QList fifo; + fifo.append(topScene); + while (!fifo.isEmpty()) { + GroupScene* scene = fifo.takeFirst(); + countItem = scene->setItemsId(countItem); + countIface = scene->setInterfacesId(countIface); + foreach(GroupScene* s, scene->getChildrenScene()) { + fifo.append(s); + } + } +} + + +ReferenceBlock *Parameters::searchBlockByXml(QString xmlName) { + foreach(ReferenceBlock *block, availableBlocks){ + if(block->getXmlFile().contains(xmlName)) + return block; + } + return NULL; +} + +ReferenceBlock *Parameters::searchBlockByMd5(QString sumMd5) { + foreach(ReferenceBlock *block, availableBlocks){ + if(block->getHashMd5() == sumMd5) + return block; + } + return NULL; +} + +void Parameters::save(QString confFile) { + +//#ifdef DEBUG_INCLFUN + + updateIds(); + QList allConnections; + QFile file(confFile); + if(file.open(QIODevice::WriteOnly)){ + + QXmlStreamWriter writer(&file); + + writer.setAutoFormatting(true); + writer.writeStartDocument(); + + writer.writeStartElement("blast_project"); + writer.writeStartElement("scenes"); + + writer.writeAttribute("count",QString::number(dispatcher->getNumberOfScenes())); + + // cross the scene level by level using a FIFO + QList fifoScene; + fifoScene.append(topScene); + foreach(ConnectionItem* item, topScene->getConnectionItems()) { + allConnections.append(item); + } + + GroupScene *scene; + while (!fifoScene.isEmpty()) { + scene = fifoScene.takeFirst(); + scene->save(writer); + foreach(GroupScene* s, scene->getChildrenScene()) { + fifoScene.append(s); + } + foreach(ConnectionItem* item, topScene->getConnectionItems()) { + allConnections.append(item); + } + } + + + writer.writeStartElement("connections"); + foreach(ConnectionItem* item, allConnections) { + + writer.writeStartElement("connection"); + + writer.writeAttribute("from",QString::number(item->getFromInterfaceItem()->getId())); + writer.writeAttribute("to", QString::number(item->getToInterfaceItem()->getId())); + + writer.writeEndElement(); + } + + writer.writeEndElement(); // + writer.writeEndElement(); //getId() == id) return scene; + GroupScene* sc = NULL; + + foreach(GroupScene *s, scene->getChildrenScene()) { + sc = searchSceneById(id,s); + if (sc != NULL) return sc; + } + return NULL; +} + +GroupItem* Parameters::searchGroupItemById(int id, GroupScene *scene) { + + if (scene->getGroupItem()->getId() == id) return scene->getGroupItem(); + + GroupItem* item = NULL; + foreach(GroupScene *s, scene->getChildrenScene()) { + item = searchGroupItemById(id,s); + if (item != NULL) return item; + } + return NULL; +} + +BoxItem* Parameters::searchBlockItemById(int id, GroupScene *scene) { + + foreach(BoxItem *item, scene->getBlockItems()){ + if(item->getId() == id){ + return item; + } + } + + BoxItem* item = NULL; + foreach(GroupScene *s, scene->getChildrenScene()) { + item = searchBlockItemById(id,s); + if (item != NULL) return item; + } + return NULL; +} + +InterfaceItem* Parameters::searchInterfaceItemById(int id, GroupScene* scene) { + + foreach(InterfaceItem *item, scene->getGroupItem()->getInterfaces()){ + if(item->getId() == id){ + return item; + } + } + foreach(BoxItem *block, scene->getBlockItems()){ + foreach(InterfaceItem *item, block->getInterfaces()){ + if(item->getId() == id){ + return item; + } + } + } + InterfaceItem* item = NULL; + foreach(GroupScene *s, scene->getChildrenScene()) { + item = searchInterfaceItemById(id,s); + if (item != NULL) return item; + } + return NULL; +} diff --git a/Parameters.h b/Parameters.h new file mode 100644 index 0000000..8393a79 --- /dev/null +++ b/Parameters.h @@ -0,0 +1,171 @@ +#ifndef __PARAMETERS_H__ +#define __PARAMETERS_H__ + +#include + +#include +#include +#include +#include +#include + +class Dispatcher; +class BlockLibraryTree; +class AbstractBlock; +class ReferenceBlock; +class GroupBlock; +class FunctionalBlock; +class GroupScene; +class GroupItem; +class BoxItem; +class InterfaceItem; +class Graph; + +#include "BlockImplementation.h" + +#include "Exception.h" +class Exception; + +// defines for current mode +#define MODE_EDITION 1 +#define MODE_ADDBLOC 2 +#define MODE_ADDCONN 3 + + +using namespace std; +using namespace Qt; + +class Parameters { + +public : + + enum Direction { NoDirection, East, North, West, South}; + + /* state of cursorn: + - CursorInBlock: cursor is within the main box of a block/group item + - CursorOnBlockBorder: cursor is on a block/group item border + - CursorOnInterface: cursor is on a block/group item Interface + - CursorOnConnection: cursor is one a connection + - CursorNowhere: none of the previous cases + */ + enum CursorState { CursorNowhere = 0, CursorInBlock, CursorInGroupTitle, CursorOnBorder, CursorOnInterface, CursorOnConnection }; + /* state of edition: + + */ + enum EditState { EditNoOperation = 0, EditBlockMove, EditBlockResize, EditGroupMove, EditGroupResize, EditInterfaceMove, EditInterfaceDeselect, EditConnectionResize, EditStartConnection, EditCloseConnection, EditAbortConnection}; + + enum XmlFileType { Configuration = 1, Reference, Implementation, Project }; + Parameters(); + ~Parameters(); + + // getter + inline GroupScene* getCurrentScene() { return currentScene; } + inline GroupScene* getTopScene() { return topScene; } + + // setter + inline void setTopScene(GroupScene* _topScene) { topScene = _topScene; } + inline void setCurrentScene(GroupScene* _currentScene) { currentScene = _currentScene; } + inline void setEditState(EditState state) { editState = state; } + inline void setCursorState(CursorState state) { cursorState = state; } + inline void setDispatcher(Dispatcher* _dispatcher) { dispatcher = _dispatcher;} + + /*************************************************** + attributes that are general to the application + ***************************************************/ + BlockLibraryTree* categoryTree; + QList refPathes; + QList implPathes; + QList availableBlocks; + QList availableImplementations; + + + QString refLib; + QString implLib; + + // defaults for vhdl + int wbDataWidth; + int wbAddressWidth; + // defaults for scene elements + int defaultBlockWidth; + int defaultBlockHeight; + QFont defaultBlockFont; + QString defaultBlockFontName; + int defaultBlockFontSize; + int arrowWidth; + int arrowHeight; + int arrowLineLength; + QFont defaultIfaceFont; + QString defaultIfaceFontName; + int defaultIfaceFontSize; + int connGapLength; + QPainterPath inArrow; + QPainterPath outArrow; + + /*************************************************** + attributes that are specific for the current project + ****************************************************/ + int sceneMode; // takes values from MODE_XXX + CursorState cursorState; + EditState editState; // takes values from EDIT_STATE_XXX + bool unsaveModif; + bool isRstClkShown; + + Graph* createGraph(); + void destroyGraph(); + inline Graph* getGraph() { return graph; } + GroupBlock* addGroupBlock(); // adding an empty GroupBlock to the current group + FunctionalBlock* addFunctionalBlock(int idCategory, int idBlock); // adding a functional block to current group + FunctionalBlock* duplicateFunctionalBlock(FunctionalBlock* block); // adding a copy of a functional block to current group + + + void clear(); + + QDomElement openProjectFile(const QString& projectFileName) throw(Exception); + void loadProject(QDomElement root); + + void loadBlastConfiguration(QString confFile) throw(Exception); + void loadReferencesFromXml() throw(Exception); + void loadReferencesFromLib() throw(Exception); + void saveReferencesToLib() throw(Exception); + + void loadImplementationsFromXml() throw(Exception); + void loadImplementationsFromLib() throw(Exception); + void saveImplementationsToLib() throw(Exception); + + void addAvailableBlock(ReferenceBlock *block); + void parametersValidation(); + void connectionsValidation(); + QList getBlocksToConfigure(); + + void updateToolbar(); + + + ReferenceBlock* searchBlockByXml(QString xmlName); + ReferenceBlock* searchBlockByMd5(QString sumMd5); + + void save(QString confFile); + + + QString projectPath; + +private: + Graph* graph; // the graph model of blocks + Dispatcher* dispatcher; + GroupScene* topScene; + GroupScene* currentScene; + + void setArrowPathes(); + void updateIds(); + + GroupScene* searchSceneById(int id, GroupScene* scene); + BoxItem* searchBlockItemById(int id, GroupScene* scene); + GroupItem* searchGroupItemById(int id, GroupScene* scene); + InterfaceItem* searchInterfaceItemById(int id, GroupScene *scene); + + void validateXmlFile(const QString& xmlFileName, const QString& xsdFileName, XmlFileType fileType) throw(Exception); + bool validate(QFile& fileXml, QFile& fileSchema); + +}; + + +#endif // __PARAMETERS_H__ diff --git a/ParametersWindow.cpp b/ParametersWindow.cpp new file mode 100644 index 0000000..07f96fa --- /dev/null +++ b/ParametersWindow.cpp @@ -0,0 +1,72 @@ +#include "ParametersWindow.h" +#include "Parameters.h" +#include "BlocksToConfigureWidget.h" +#include "BlockParameter.h" +#include "AbstractBlock.h" + +ParametersWindow::ParametersWindow(AbstractBlock *_block, Parameters *_params, BlocksToConfigureWidget *btcw, QWidget *parent) : + QWidget(parent) +{ + block = _block; + confWidget = btcw; + params = _params; + + layout = new QGridLayout; + + name = new QLabel; + value = new QLineEdit; + context = new QLabel; + type = new QLabel; + + comboBox = new QComboBox; + + foreach(BlockParameter *param, block->getParameters()){ + comboBox->addItem(param->getName()); + } + connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateData())); + updateData(); + + saveButton = new QPushButton("Save"); + connect(saveButton, SIGNAL(clicked()), this, SLOT(save())); + + layout->addWidget(new QLabel("Parameters"), 0, 0); + layout->addWidget(comboBox, 0, 1); + + layout->addWidget(new QLabel(" "), 1, 0); + + layout->addWidget(new QLabel("Name"), 2, 0); + layout->addWidget(name, 2, 1); + layout->addWidget(new QLabel("Value"), 3, 0); + layout->addWidget(value, 3, 1); + layout->addWidget(new QLabel("Context"), 4, 0); + layout->addWidget(context, 4, 1); + layout->addWidget(new QLabel("Type"), 5, 0); + layout->addWidget(type, 5, 1); + + layout->addWidget(saveButton, 6, 0); + + this->setLayout(layout); + + show(); +} + +void ParametersWindow::updateData() +{ + BlockParameter *param = block->getParameters().at(comboBox->currentIndex()); + name->setText(param->getName()); + value->setText(param->getValue().toString()); + context->setText(param->getContext()); + type->setText(param->getTypeString()); +} + +void ParametersWindow::save() +{ + BlockParameter *param = block->getParameters().at(comboBox->currentIndex()); + param->setValue(value->text()); + + //params->parametersValidation(); + if(confWidget != NULL){ + confWidget->updateBlocksList(); + } + close(); +} diff --git a/ParametersWindow.h b/ParametersWindow.h new file mode 100644 index 0000000..df6e4fc --- /dev/null +++ b/ParametersWindow.h @@ -0,0 +1,34 @@ +#ifndef __PARAMETERSWINDOW_H__ +#define __PARAMETERSWINDOW_H__ + +#include + +class Parameters; +class AbstractBlock; +class BlocksToConfigureWidget; + +class ParametersWindow : public QWidget { + Q_OBJECT + +public: + ParametersWindow(AbstractBlock *block, Parameters *_params, BlocksToConfigureWidget *btcw=NULL, QWidget *parent=0); + +private: + AbstractBlock *block; + Parameters *params; + BlocksToConfigureWidget *confWidget; + QGridLayout *layout; + QComboBox *comboBox; + QLabel *name; + QLabel *context; + QLineEdit *value; + QLabel *type; + QPushButton *saveButton; + +private slots: + void updateData(); + void save(); + +}; + +#endif // PARAMETERSWINDOW_H diff --git a/ReferenceBlock.cpp b/ReferenceBlock.cpp new file mode 100644 index 0000000..8b50bfa --- /dev/null +++ b/ReferenceBlock.cpp @@ -0,0 +1,471 @@ +#include "ReferenceBlock.h" + +#include "ReferenceInterface.h" +#include "BlockParameter.h" +#include "BlockParameterUser.h" +#include "BlockParameterGeneric.h" +#include "BlockParameterPort.h" +#include "BlockParameterWishbone.h" + +ReferenceBlock::ReferenceBlock(const QString _xmlFile) : AbstractBlock() { + xmlFile = _xmlFile; +} + +void ReferenceBlock::addCategory(int id) { + categories.append(id); +} + +void ReferenceBlock::setBriefDescription(const QString& str) { + if(str != NULL) + descriptionBrief = str; +} + +void ReferenceBlock::setDetailedDescription(const QString& str) { + if(str != NULL) + descriptionDetail = str; +} + +void ReferenceBlock::addImplementation(BlockImplementation *impl) { + implementations.append(impl); +} + +void ReferenceBlock::setHashMd5() { + QFile file(xmlFile); + if (file.open(QIODevice::ReadOnly)) { + QByteArray fileData = file.readAll(); + QByteArray hashData = QCryptographicHash::hash(fileData, QCryptographicHash::Md5); + hashMd5 = QString(hashData.toHex()); + cout << qPrintable(xmlFile) << " has md5 hash : " << qPrintable(hashMd5) << endl; + } + else { + hashMd5 = ""; + } +} + +void ReferenceBlock::load(QDomElement &elt) throw(Exception) { + + + cout << "Block : get informations" << endl; + QDomElement eltInfo = elt.firstChildElement("informations"); + try { + loadInformations(eltInfo); + } + catch(int err) { + throw(err); + } + + cout << "Block : get params" << endl; + QDomElement eltParams = eltInfo.nextSiblingElement("parameters"); + try { + loadParameters(eltParams); + } + catch(int err) { + throw(err); + } + + cout << "Block : get interfaces" << endl; + QDomElement eltInter = eltParams.nextSiblingElement("interfaces"); + try { + loadInterfaces(eltInter); + } + catch(int err) { + throw(err); + } +} + +void ReferenceBlock::loadInformations(QDomElement &elt) throw(Exception) { + + bool ok; + if ((elt.isNull()) || (elt.tagName() != "informations")) throw (Exception(BLOCKFILE_CORRUPTED)); + // getting name + cout << "Block info : get name" << endl; + QDomNode nodeName = elt.firstChild(); + QDomNode nodeNameTxt = nodeName.firstChild(); + if (nodeNameTxt.isNull()) { + name = "no_name"; + } + else { + QDomText txtName = nodeNameTxt.toText(); + name = txtName.data().trimmed(); + cout<< "block name : " << qPrintable(name) << endl; + } + + // getting categories + cout << "Block info : get categories" << endl; + QDomElement eltCat = nodeName.nextSiblingElement("category"); + + QString idsStr = eltCat.attribute("ids","none"); + if (idsStr == "none") throw (Exception(BLOCKFILE_CORRUPTED)); + QStringList listCat = idsStr.split(","); + foreach(QString str, listCat) + { + int idCat = str.toInt(&ok); + categories.append(idCat); + } + + // getting description + cout << "Block info : get description" << endl; + QDomElement eltDesc = eltCat.nextSiblingElement("description"); + // getting brief + QDomElement eltBrief = eltDesc.firstChildElement("brief"); + QDomNode nodeBriefTxt = eltBrief.firstChild(); + if (nodeBriefTxt.isNull()) { + descriptionBrief = "no brief description"; + } + else { + QDomText txtBrief = nodeBriefTxt.toText(); + descriptionBrief = txtBrief.data().trimmed(); + cout << "block brief desc : " << qPrintable(descriptionBrief) << endl; + } + // getting detailed + QDomElement eltDetail = eltBrief.nextSiblingElement("detailed"); + QDomNode nodeDetailTxt = eltDetail.firstChild(); + if (nodeDetailTxt.isNull()) { + descriptionDetail = "no detailed description"; + } + else { + QDomText txtDetail = nodeDetailTxt.toText(); + descriptionDetail = txtDetail.data().trimmed(); + cout << "block detail desc : " << qPrintable(descriptionDetail) << endl; + } +} + +void ReferenceBlock::loadParameters(QDomElement &elt) throw(Exception) { + + if ((elt.isNull()) || (elt.tagName() != "parameters")) throw (Exception(BLOCKFILE_CORRUPTED)); + + QDomNodeList listNodeParam = elt.elementsByTagName("parameter"); + for(int i=0; igetName().toStdString() << endl; + cout << "purpose for " << nameStr.toStdString() << " : " << purposeStr.toStdString() << endl; + purpose = ReferenceInterface::translatePurpose(purposeStr); + cout << "translated purpose : " << purpose << endl; + levelStr = eltInput.attribute("level","none"); + level = ReferenceInterface::translateLevel(levelStr); + multStr = eltInput.attribute("multiplicity","none"); + mult = ReferenceInterface::translateMultiplicity(multStr); + + inter = new ReferenceInterface(this,nameStr,typeStr,widthStr,AbstractInterface::Input, purpose, level, mult); + inputs.append(inter); + } + + QDomElement eltOutputs = eltInputs.nextSiblingElement("outputs"); + QDomNodeList listNodeOutputs = eltOutputs.elementsByTagName("output"); + for(int i=0;i *checkedBlocks, QList *blocksToConfigure) +{ + return; +} + +/* operator<<() : + only used to save all ReferenceBlock in a library in binary format, so that reference blocks + are read very fast at application startup. + + */ +QDataStream& operator<<(QDataStream &out, const ReferenceBlock &b) { + + out.setVersion(QDataStream::Qt_5_0); + + QByteArray blockData; + QDataStream toWrite(&blockData, QIODevice::WriteOnly); + + toWrite << b.name; + toWrite << b.xmlFile; + toWrite << b.descriptionBrief; + toWrite << b.descriptionDetail; + toWrite << b.categories; + toWrite << b.hashMd5; + toWrite << b.params.size(); + BlockParameter* p; + for(int i=0;igetContext(); + toWrite << p->getName(); + toWrite << p->getTypeString(); + toWrite << p->getValue().toString(); + if (p->isPortParameter()) { + toWrite << ((BlockParameterPort*)p)->getIfaceName(); + } + else if (p->isWishboneParameter()) { + BlockParameterWishbone* pwb = (BlockParameterWishbone*)p; + toWrite << pwb->getWidth(); + toWrite << pwb->getWBAccess(); + toWrite << pwb->getWBValue(); + toWrite << pwb->getWBDuration(); + } + + } + + toWrite << b.inputs.size(); + for(int i=0; igetName(); + toWrite << iface->getWidth(); + toWrite << iface->getPurpose(); + toWrite << iface->getDirection(); + toWrite << iface->getLevel(); + toWrite << iface->getMultiplicity(); + } + toWrite << b.outputs.size(); + for(int i=0; igetName(); + toWrite << iface->getWidth(); + toWrite << iface->getPurpose(); + toWrite << iface->getDirection(); + toWrite << iface->getLevel(); + toWrite << iface->getMultiplicity(); + } + toWrite << b.bidirs.size(); + for(int i=0; igetName(); + toWrite << iface->getWidth(); + toWrite << iface->getPurpose(); + toWrite << iface->getDirection(); + toWrite << iface->getLevel(); + toWrite << iface->getMultiplicity(); + } + + out << blockData; + + return out; +} + +QDataStream& operator>>(QDataStream &in, ReferenceBlock &b) { + + quint32 blockSize; + ReferenceInterface* iface; + BlockParameter* p; + int val; + QString txt=""; + + in.setVersion(QDataStream::Qt_5_0); + + in >> blockSize; + + in >> b.name; + in >> b.xmlFile; + in >> b.descriptionBrief; + in >> b.descriptionDetail; + in >> b.categories; + in >> b.hashMd5; + b.params.clear(); + int nb; + in >> nb; + cout << qPrintable(b.name) << " has " << nb << " parameters" << endl; + for(int i=0;i> contextStr; + in >> nameStr; + in >> typeStr; + in >> valueStr; + + if (contextStr == "user") { + p = new BlockParameterUser(&b,nameStr,valueStr); + } + else if (contextStr == "generic") { + p = new BlockParameterGeneric(&b,nameStr,typeStr,valueStr); + } + else if (contextStr == "port") { + QString ifaceStr = ""; + in >> ifaceStr; + p = new BlockParameterPort(&b,nameStr,valueStr,ifaceStr); + } + else if (contextStr == "wb") { + QString widthStr = ""; + int wbAccess; + QString wbValue; + int wbDuration; + in >> widthStr; + in >> wbAccess; + in >> wbValue; + in >> wbDuration; + p = new BlockParameterWishbone(&b,nameStr,typeStr,widthStr,valueStr,wbAccess,wbValue,wbDuration); + } + b.params.append(p); + } + + b.inputs.clear(); + in >> nb; + for(int i=0;i> txt; + iface->setName(txt); + in >> txt; + iface->setWidth(txt); + in >> val; + iface->setPurpose(val); + in >> val; + iface->setDirection(val); + in >> val; + iface->setLevel(val); + in >> val; + iface->setMultiplicity(val); + b.inputs.append(iface); + } + + b.outputs.clear(); + in >> nb; + for(int i=0;i> txt; + iface->setName(txt); + in >> txt; + iface->setWidth(txt); + in >> val; + iface->setPurpose(val); + in >> val; + iface->setDirection(val); + in >> val; + iface->setLevel(val); + in >> val; + iface->setMultiplicity(val); + b.outputs.append(iface); + } + + b.bidirs.clear(); + in >> nb; + for(int i=0;i> txt; + iface->setName(txt); + in >> txt; + iface->setWidth(txt); + in >> val; + iface->setPurpose(val); + in >> val; + iface->setDirection(val); + in >> val; + iface->setLevel(val); + in >> val; + iface->setMultiplicity(val); + b.bidirs.append(iface); + } + + return in; +} diff --git a/ReferenceBlock.h b/ReferenceBlock.h new file mode 100644 index 0000000..324e289 --- /dev/null +++ b/ReferenceBlock.h @@ -0,0 +1,69 @@ +#ifndef __REFERENCEBLOCK_H__ +#define __REFERENCEBLOCK_H__ + +#include + +#include +#include +#include +#include + +#include "AbstractBlock.h" +class AbstractBlock; + +#include "BlockImplementation.h" + +#include "Exception.h" +class Exception; + +using namespace std; +using namespace Qt; + + +class ReferenceBlock : public AbstractBlock { + +public: + + ReferenceBlock(const QString _xmlFile); + + int getType(); + inline QString getXmlFile() { return xmlFile; } + inline QString getBriefDescription() { return descriptionBrief; } + inline QString getDetailedDescription() { return descriptionDetail; } + inline QList getCategories() { return categories; } + inline QList getImplementations() { return implementations; } + inline QString getHashMd5() { return hashMd5; } + + inline AbstractBlock* getParent() { return NULL; } + + void addCategory(int id); + void setBriefDescription(const QString& str); + void setDetailedDescription(const QString& str); + void addImplementation(BlockImplementation* impl); + + void load(QDomElement &elt) throw(Exception); + void setHashMd5(); + +private: + QString xmlFile; // the xml file from which attributes are initialized. + QString hashMd5; + QString descriptionBrief; + QString descriptionDetail; + QList categories; + QList implementations; // set when implementations are read + + // loading methods for the different tags in the XML desc. + void loadInformations(QDomElement &elt) throw(Exception); + void loadParameters(QDomElement &elt) throw(Exception); + void loadInterfaces(QDomElement &elt) throw(Exception); + + friend QDataStream &operator<<(QDataStream &out, const ReferenceBlock &b); + friend QDataStream &operator>>(QDataStream &in, ReferenceBlock &b); + + + // AbstractBlock interface +public: + void parametersValidation(QList* checkedBlocks, QList* blocksToConfigure); +}; + +#endif // __REFERENCEBLOCK_H__ diff --git a/ReferenceInterface.cpp b/ReferenceInterface.cpp new file mode 100644 index 0000000..8aca132 --- /dev/null +++ b/ReferenceInterface.cpp @@ -0,0 +1,73 @@ +#include "ReferenceInterface.h" +#include "AbstractBlock.h" + +ReferenceInterface::ReferenceInterface(AbstractBlock* _owner) throw(Exception) : AbstractInterface(_owner) { + if (_owner->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + multiplicity = 1; +} + +ReferenceInterface::ReferenceInterface(AbstractBlock* _owner, + const QString& _name, const QString&_type, + const QString& _width, + int _direction, + int _purpose, + int _level, + int _multiplicity) +throw (Exception) : AbstractInterface(_owner, _name, _type, _width, _direction, _purpose, _level) { + + if (_owner->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE)); + + multiplicity = _multiplicity; + if (direction == InOut) { + multiplicity = 1; + } +} + +bool ReferenceInterface::isReferenceInterface() { + return true; +} + +void ReferenceInterface::setMultiplicity(int _multiplicity) { + if (direction == InOut) { + multiplicity = 1; + } + else { + multiplicity = _multiplicity; + } +} + +int ReferenceInterface::translatePurpose(const QString& txt) { + if (txt == "clock") { + return Clock; + } + else if (txt == "reset") { + return Reset; + } + if (txt == "wb") { + return Wishbone; + } + return Data; +} + +int ReferenceInterface::translateLevel(const QString& txt) { + + if (txt == "top") { + return Top; + } + return Basic; +} + +int ReferenceInterface::translateMultiplicity(const QString& txt) { + bool ok; + int mult; + if (txt == "*") { + mult = -1; + } + else { + mult = txt.toInt(&ok); + if (!ok) { + mult = 1; + } + } + return mult; +} diff --git a/ReferenceInterface.h b/ReferenceInterface.h new file mode 100644 index 0000000..cd5bd0f --- /dev/null +++ b/ReferenceInterface.h @@ -0,0 +1,48 @@ +#ifndef __REFERENCEINTERFACE_H__ +#define __REFERENCEINTERFACE_H__ + +#include + +#include +#include + +#include "AbstractInterface.h" + +#include "Exception.h" + +using namespace std; +using namespace Qt; + + +class ReferenceInterface : public AbstractInterface { + +public : + + ReferenceInterface(AbstractBlock *_owner) throw(Exception); + ReferenceInterface(AbstractBlock* _owner, const QString& _name, const QString& _type, const QString& _width, int _direction, int _purpose, int _level, int _multiplicity=1) throw (Exception); + + // getters + inline int getMultiplicity() { return multiplicity; } + inline AbstractInterface* getConnectedFrom() { return NULL; } + // setters + void setMultiplicity(int _multiplicity); + + // testers + bool isReferenceInterface(); + + // others + + static int translatePurpose(const QString& txt); + static int translateLevel(const QString& txt); + static int translateMultiplicity(const QString& txt); + + inline AbstractInterface *clone(){ return NULL; } + + +private: + int multiplicity; // -1 means infinite multiplicity, and X>1, the max. number of instances + + +}; + +#endif // __REFERENCEINTERFACE_H__ diff --git a/Toto.cpp b/Toto.cpp new file mode 100644 index 0000000..0e5fb15 --- /dev/null +++ b/Toto.cpp @@ -0,0 +1,12 @@ +#include "Toto.h" + +#include "FunctionalBlock.h" +#include "ReferenceBlock.h" +#include "ReferenceInterface.h" +#include "FunctionalInterface.h" +#include "BlockParameter.h" + + +Toto::Toto(const QString& msg) { + v = msg; +} diff --git a/Toto.h b/Toto.h new file mode 100644 index 0000000..1980e26 --- /dev/null +++ b/Toto.h @@ -0,0 +1,35 @@ +#ifndef __TOTO_H__ +#define __TOTO_H__ + +#include +#include + +#include +#include + +class ReferenceBlock; +class FunctionalBlock; +class AbstractInterface; + + +#include "ArithmeticEvaluator.h" +class ArithmeticEvaluator; + +#include "Exception.h" +class Exception; + +using namespace std; +using namespace Qt; + +class Toto { + +public: + + Toto(const QString& msg); + +private: + QString v; +}; + +#endif // __TOTO_H__ + diff --git a/blast-tg.odt b/blast-tg.odt new file mode 100755 index 0000000..c85bfeb Binary files /dev/null and b/blast-tg.odt differ diff --git a/blast.config b/blast.config new file mode 100755 index 0000000..e0284f4 --- /dev/null +++ b/blast.config @@ -0,0 +1,2 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 diff --git a/blast.cpp b/blast.cpp new file mode 100644 index 0000000..b205eb2 --- /dev/null +++ b/blast.cpp @@ -0,0 +1,18 @@ +#include +#include +#include "MainWindow.h" +#include + +using namespace std; +using namespace Qt; + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + + w.show(); + + return a.exec(); + +} diff --git a/blast.creator b/blast.creator new file mode 100755 index 0000000..e94cbbd --- /dev/null +++ b/blast.creator @@ -0,0 +1 @@ +[General] diff --git a/blast.creator.user b/blast.creator.user new file mode 100755 index 0000000..9b8a007 --- /dev/null +++ b/blast.creator.user @@ -0,0 +1,193 @@ + + + + + + EnvironmentId + {3701e197-5b6c-48ea-9e98-a6cf6de18672} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ed04208c-8774-456b-99b9-4a02094ca7a4} + 0 + 0 + 0 + + /home/sdomas/Projet/Blast/code/v0.2 + + + + all + + false + + + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Compiler + + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + + + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Nettoyer + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Défaut + Défaut + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Déploiement + + ProjectExplorer.BuildSteps.Deploy + + 1 + Déployer localement + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + + false + %{buildDir} + Exécutable personnalisé + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 16 + + + Version + 16 + + diff --git a/blast.files b/blast.files new file mode 100755 index 0000000..7b2dd43 --- /dev/null +++ b/blast.files @@ -0,0 +1,73 @@ +Exception.h +Exception.cpp +AbstractBlock.h +AbstractBlock.cpp +AbstractBoxItem.h +AbstractBoxItem.cpp +FunctionalBlock.cpp +FunctionalBlock.h +GroupBlock.h +GroupBlock.cpp +BlockImplementation.h +BlockImplementation.cpp +GroupScene.cpp +GroupScene.h +ReferenceBlock.cpp +ReferenceBlock.h +AbstractInterface.h +AbstractInterface.cpp +ConnectedInterface.h +ConnectedInterface.cpp +ReferenceInterface.h +ReferenceInterface.cpp +FunctionalInterface.cpp +FunctionalInterface.h +GroupInterface.h +GroupInterface.cpp +BlockLibraryWidget.cpp +BlockLibraryWidget.h +blast.cpp +BlockCategory.cpp +BlockCategory.h +BoxItem.cpp +BoxItem.h +BlockLibraryTree.cpp +BlockLibraryTree.h +BlockParameter.cpp +BlockParameter.h +BlockParameterUser.h +BlockParameterUser.cpp +BlockParameterGeneric.h +BlockParameterGeneric.cpp +BlockParameterWishbone.h +BlockParameterWishbone.cpp +BlockParameterPort.h +BlockParameterPort.cpp +Dispatcher.cpp +Dispatcher.h +Graph.cpp +Graph.h +MainWindow.cpp +MainWindow.h +Parameters.cpp +Parameters.h +ConnectionItem.h +ConnectionItem.cpp +InterfaceItem.h +InterfaceItem.cpp +GroupItem.h +GroupItem.cpp +Abstractblockitem.h +Abstractblockitem.cpp +GroupWidget.h +GroupWidget.cpp +BlockWidget.cpp +BlockWidget.h +BlocksToConfigureWidget.h +BlocksToConfigureWidget.cpp +ParametersWindow.h +ParametersWindow.cpp +ArithmeticEvaluator.cpp +ArithmeticEvaluator.h +InterfacePropertiesWindow.h +InterfacePropertiesWindow.cpp diff --git a/blast.ico b/blast.ico new file mode 100755 index 0000000..6f1794d Binary files /dev/null and b/blast.ico differ diff --git a/blast.includes b/blast.includes new file mode 100755 index 0000000..97e709e --- /dev/null +++ b/blast.includes @@ -0,0 +1,15 @@ +. +/usr/include/x86_64-linux-gnu/qt5/QtCore +/usr/include/x86_64-linux-gnu/qt5/QtGui +/usr/include/x86_64-linux-gnu/qt5/QtWidgets +/usr/include/x86_64-linux-gnu/qt5/QtNetwork +/usr/include/x86_64-linux-gnu/qt5/QtXml +/usr/include/x86_64-linux-gnu/qt5/QtXmlPatterns +/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport +C:\Qt\5.4\mingw491_32\include\QtCore +C:\Qt\5.4\mingw491_32\include\QtGui +C:\Qt\5.4\mingw491_32\include\QtWidgets +C:\Qt\5.4\mingw491_32\include\QtXml +C:\Qt\5.4\mingw491_32\include\QtXmlPatterns +C:\Qt\5.4\mingw491_32\include\QtPrintSupport +C:\MinGW\include diff --git a/blast.qrc b/blast.qrc new file mode 100755 index 0000000..9f1e539 --- /dev/null +++ b/blast.qrc @@ -0,0 +1,24 @@ + + + icons/copy.png + icons/cut.png + icons/delete.png + icons/inter_add.png + icons/link.png + icons/paste.png + icons/save.png + icons/redo-icon.png + icons/undo.png + icons/save-as.png + icons/open.png + icons/load.png + icons/window_new.png + icons/new.ico + icons/folder_add_16.png + icons/add_block.png + icons/edit_block.png + icons/add_group_void.png + icons/add_group_select.png + icons/add_connection.png + + diff --git a/blast.rc b/blast.rc new file mode 100755 index 0000000..c6b4512 --- /dev/null +++ b/blast.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "blast.ico" \ No newline at end of file diff --git a/blastconfig.xml b/blastconfig.xml new file mode 100644 index 0000000..a8184b8 --- /dev/null +++ b/blastconfig.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blastconfig.xsd b/blastconfig.xsd new file mode 100644 index 0000000..f254ff6 --- /dev/null +++ b/blastconfig.xsd @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/block-1I1O.xml b/block-1I1O.xml new file mode 100644 index 0000000..32efdb5 --- /dev/null +++ b/block-1I1O.xml @@ -0,0 +1,34 @@ + + + + + block-1I1O + + + + + A testing block with 1 input, 1 output + + + A testing block with 1 input, 1 output + + + + + + + + + + + + + + + + + + + + + diff --git a/block-2I2O.xml b/block-2I2O.xml new file mode 100644 index 0000000..54c5460 --- /dev/null +++ b/block-2I2O.xml @@ -0,0 +1,36 @@ + + + + + block-2I2O + + + + + A testing block with 2 inputs, 2 outputs + + + A testing block with 2 inputs, 2 outputs + + + + + + + + + + + + + + + + + + + + + + + diff --git a/block-2INO.xml b/block-2INO.xml new file mode 100644 index 0000000..d654234 --- /dev/null +++ b/block-2INO.xml @@ -0,0 +1,35 @@ + + + + + block-2INO + + + + + A testing block with 2 inputs, N outputs + + + A testing block with 2 inputs, N outputs + + + + + + + + + + + + + + + + + + + + + + diff --git a/block.xsd b/block.xsd new file mode 100644 index 0000000..42c82ef --- /dev/null +++ b/block.xsd @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/models-tg.pdf b/doc/models-tg.pdf new file mode 100644 index 0000000..86606a7 Binary files /dev/null and b/doc/models-tg.pdf differ diff --git a/doc/models-tg.tex b/doc/models-tg.tex new file mode 100644 index 0000000..fd39c6f --- /dev/null +++ b/doc/models-tg.tex @@ -0,0 +1,376 @@ +\documentclass[12pt,fleqn,a4paper]{article} +\usepackage[latin1]{inputenc} +%\usepackage[cyr]{aeguill} +\usepackage{xspace} +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage[english]{babel} +\usepackage{url} +\usepackage{multirow} +\let\urlorig\url +\renewcommand{\url}[1]{% + \begin{otherlanguage}{english}\urlorig{#1}\end{otherlanguage}% +} + +%\usepackage{pstricks,pst-node,pst-text,pst-3d} +\usepackage{graphicx} +\usepackage{thumbpdf} +\usepackage{color} +\usepackage{moreverb} +%\usepackage{commath} +\usepackage{subfigure} +%\input{psfig.sty} +\usepackage{fullpage} +\usepackage{fancybox} + +\usepackage[ruled,lined,linesnumbered]{algorithm2e} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands. +\newcommand{\noun}[1]{\textsc{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% my own LaTeX commands. +%\newcommand{\bibpath}[1] +% {/home/sdomas/rapport/eigenjace/ipdps/#1} + +\newcommand{\tab}{\ \ \ } +\newcommand{\ot}[1]{{\tt #1}} +%%%%%%%%%%%%%%%%%%%%%%%%%%%% my bib path. + + +\title{BLAST: classes and xml files for blocks (models, implementations and view)} + +\author{St\'ephane Domas\\ +Laboratoire d'Informatique +de l'Universit\'e de Franche-Comt\'e, \\ +BP 527, \\ +90016~Belfort CEDEX, France\\} + + + +\begin{document} + +\maketitle + +\thispagestyle{empty} +\section{What are blocks and items ?} +A block is the main unit to build a design in Blast. From the user +point of view, a block represents a process with inputs to consume +data, outputs to produce results. It may have some parameters +(e.g. the input/output data size). Thus, the user is not concerned +about how the block is really implemented in VHDL, just about the +"function" of the block. Some blocks are predefined, but the user can +also build them by composing predefined ones. + +For the first type, the user has to choose the predefined blocks from +a library of "reference blocks" that do a particular processing +(i.e. a multiplication, a filter, ...), with default interface names +and parameter values. To add such a block to the design, a reference +block is cloned to obtain a "functional" block. It is similar to the +instanciation in object oriented programming: reference block +corresponds to the class, and functional block to the instance of that +class. Thus, a design may contain several functional blocks that +correspond to the same reference block. A reference block is +associated to one or several implementations that are in fact patterns +of VHDL code. One of them will be chosen more or less automatically by +Blast to produce the final VHDL code. The representation of an +implementation as a class and the structure of the files that contain +patterns are discussed in details in Section \ref{Implementations}. + +The second type is named a "group" block. It is created empty or with +a set of existing functional blocks. For example, when a void design +is created, a group block is also created, that will represent the top +component in the VHDL code. User can add predefined blocks or even +other group blocks within a group very easily. There main purpose is +to make the design clearer and the VHDL more readable. Indeed, each +group will be translated into a VHDL component. Thus, instead of +having a single top component with a bunch of predefined blocks +within, they can be spread within groups to build a design +hierachically. + +These three types of block are represented by a hierarchy of classes +that is described in details in Section \ref{sec:blocks_class}.\\ + +Reference, functional and group blocks are just containers of data, +i.e. they are part of the Model in MVC paradigm). The two latter have +a graphical counter part, named items, so that they can be represented +in the graphical interface. The hierarchy of classes +that represents the items is described in details in Section \ref{sec:items_class}.\\ + +\section{Class hierarchy for blocks} +\label{sec:blocks_class} + +\subsection{the top class} +\label{sec:abstract_block_class} + +The top class for describing block is {\tt AbstractBlock}, derived in +three subclasses: {\tt ReferenceBlock}, {\tt FunctionalBlock}, {\tt + GroupBlock}. + +Some attributes are common to every types, and defined in {\tt AbstractBlock}: +\begin{itemize} +\item a name, +\item parameters, +\item input/output/bidirectional interfaces. +\end{itemize} + +Parameters and interfaces are complex to represent and thus, are also +described by a hierarchy of classes in Section +\ref{sec:parameters_class} and \ref{sec:interfaces_class}. + +\subsection{reference blocks} +\label{sec:reference_block_class} + +A reference block is created taking informations in an XML file that +describes it, providing its parameters and interfaces. The structure +of that file is described in details in Section +\ref{sec:references_xml}. + +A reference block also contains a list of {\tt + BlockImplementation}. Each of them represents a pattern of VHDL code +that implements the function of the block. + +\subsection{functional blocks} +\label{sec:functional_block_class} + +A functional block has two attributes {\tt reference} and {\tt group} +that respectively refer to the reference block that has been cloned to +create that functional block, and the group block that contains it. + + +\subsection{group blocks} +\label{sec:group_block_class} + +A group block has mainly two attributes {\tt parent} and {\tt + blocks}. The first one is a pointer to the group that contains that +group (or {\tt NULL} if it is the top group). The second one is the +list of the functional or group blocks that are within this group. + +{\bf Important: } a group block has no interface by itself. In fact, +they are created when the user wants to connect an interface of a +inner block to the outside of the block. Note that there is a 1:1 +relation between a group interface and an interface of an inner +block. Nevertheless, an output group interface can still be connected +to several input interfaces. + +{\bf Important: } a group block has no parameters by itself, except +if it contains blocks that may be configured via a wishbone. In this +case, the generic parameters to manage the wishbone are atuomaticcaly +added to the group. + +\subsection{interfaces classes} +\label{sec:interfaces_class} + +As for blocks, a top class {\tt AbstractInterface} represents the +common features of all interfaces and it is derived in three +subclasses: {\tt ReferenceInterface}, {\tt FunctionalInterface} and +{\tt GroupInterface}. + +\subsection{parameters classes} +\label{sec:parameters_class} + + +There are four types of parameters for a block: +\begin{itemize} +\item user, +\item generic, +\item port, +\item wishbone. +\end{itemize} + +These are represented by the top class {\tt BlockParameter} and four +subclasses: ({\tt BlockParameterUSer}, {\tt BlockParameterGeneric}, +{\tt BlockParameterPort}, {\tt BlockParameterWishbone}. + +Four attributes are common to all, and defined in {\tt BlockParameter}: +\begin{itemize} +\item \ot{owner}: a pointer to the block instance (reference/functional) that ``owns'' this parameter, +\item \ot{name}: the name of the parameter (NB: cannot be changed by the user of BLAST), +\item \ot{type}: the type of the value, +\item \ot{value}: the default value of the parameter, given as a \ot{QString} but stored as a \ot{QVariant}. +\end{itemize} + +\ot{type} value (int) must be set with one of those in \ot{ParamType} enum (cf. \ot{BlockParameter.h}): + +\begin{verbatim} +enum ParamType { Undefined = -1, Expression = 1, Character, + String, Bit, BitVector, Boolean, + Integer, Natural, Positive, Real, Time}; +\end{verbatim} +Except the two first, these values correspond to predefined types in +VHDL. \ot{Expression} correspond to an arithmetic expression and must +be used only for port and wishbone parameters. Thus, its syntax will +be presented in the associated sections (\ref{sec:parameters_port} and +\ref{parameters_wb}).\\ + +Whatever the case, parameters will be used during VHDL generation but at different phases, depending on the class. + +\subsubsection{user parameters} +\label{sec:parameters_user} +User parameters have a type equals to \ot{String}. A default value +must be given at construction but a \ot{userValue} can be defined via +setters.\\ + +A user parameter is only used when generating the VHDL code of the +architecture section of a block (cf. section +\ref{sec:impls_xml}). Each time the generator encounters an escape +sequence: \ot{@val\{user\_parameter\_name\}}, it replaces it with +\ot{userValue} if defined, or with the default value.\\ + +{\bf CAUTION:} No validity check are done by BLAST on default and user +value strings. Thus, they can be anything and can lead to incorrect +VHDL. + +\subsubsection{generic parameters} +\label{sec:parameters_generic} + +Generic parameters have a type equals to any predefined VHDL type (i.e. all +defined above except \ot{Undefined} and \ot{Expression}). A default +value must be given at construction but a \ot{userValue} can be +defined via setters.\\ + +A generic parameter is used during the generation of: +\begin{itemize} +\item the entity section, +\item the component section when the owner block is used within another block, +\item the generic map of when instanciating owner block is used within another block, +\item the architecture section. +\end{itemize} + +In the two first cases, it leads to lines like + +\ot{d\_width : integer := 16;}, using the \ot{name}, \ot{type} and default value. + +In the third case, it leads to lines like + +\ot{d\_width => 10,}, using the \ot{name} and \ot{userValue}, +or default value if not defined. + +\ot{d\_width => d\_width,}, using only the +\ot{name}. This case occurs when the owner is instanciated within a +block that has a generic parameter with the same name. + +In the last case, each time the generator encounters an escape +sequence: \ot{@val\{generic\_parameter\_name\}}, it replaces it with +\ot{userValue} if defined, or with the default value.\\ + +{\bf IMPORTANT:} a block that defines wishbone parameters will be +generated with 2 generic parameters with predefined names: +\ot{wb\_data\_width} and \ot{wb\_addr\_width}. They correspond to the +width of the address and data buses of the wishbone and are used +during the generation of the controller of the block +(cf. \ref{sec:parameters_wb}). + +\subsubsection{port parameters} +\label{sec:parameters_port} +A port parameter can be used to obtain a value associated to an +interface of the block. Indeed, it is possible to create several +instances of the same interface, when its multiplicity given in the +reference model is greater than 1. For example, it is used for block +that may have a variable number of inputs/outputs, like a +multiplexer. Instead fo creating a bunch of multiplexers with 2, 3, 4, +$\ldots$ data inputs, it is possible to generate one for any +amount. In BLAST, this amount is given by the number of instances of +the data input the user has created. It implies that the selector +input has a variable range and thus needs a variable number of bits to +be expressed. If $N$ is the number of instances of the data input, +then the selector size is $log_2(N)$. A port parameter is used to +express such a value.\\ + +A port parameters have a supplementary attribute \ot{ifaceName} that +must correspond to an existing interface of the block. \ot{type} is +equal to \ot{Expression} and \ot{value} contains this expression, +using variables with a predefined name \ot{\$if\_nb} and +\ot{\$if\_width} that will be respectively replace during VHDL +generation by the number of instances of \ot{ifaceName}, and its +width. + +A port parameter is used during the generation of: +\begin{itemize} +\item the entity section, +\item the component section when the owner block is used within another block, +\item the architecture section. +\end{itemize} + +In every case, each time the generator encounters an escape sequence: +\ot{@val\{port\_parameter\_name\}}, it replaces it with the computed +value of the parameter using the expression and the interface name. + + +\subsubsection{wishbone parameters} +\label{sec:parameters_wb} + +A wishbone parameter corresponds to a register that can be read/write +via the wishbone bus. Nevertheless, the GUI allows the user to disable +the wishbone access and replace it by a fixed value or a port that is +assign to the register. + +Since a register has a width, \ot{type} gives its type. Valid types are: +\begin{itemize} +\item \ot{boolean} if the register is an \ot{std\_logic}, +\item \ot{natural} if the register has a fixed width and is a \ot{std\_logic\_vector}, +\item \ot{expression} if the register has a variable width and is a \ot{std\_logic\_vector}, +\end{itemize} +The width is given in a supplementary attribute \ot{width}. Note that: +\begin{itemize} +\item if the type is boolean, width should be equal to 1 but in fact is not used. + +\item if the type is natural and width is equal to 1, it leads to +\ot{std\_logic\_vector(0 downto 0)}, which is sometimes usefull for +memory accesses. + +\item if the type is an expression, width must contains an expression + using only +,-,*, numbers and generic parameter references + (i.e. parameter name prepend with a $). No check is done thus, the + model must be correct so that valid VHDL will be produced. +\end{itemize} + +In the second case, the expression may use predefined names +\ot{wb\_data\_width} and \ot{wb\_addr\_width}. + +Whatever the case, during VHDL generation, the final width will be +compared to the wishbone data bus width. If the bus width is lesser +than the register width, then several wishbone accesses are needed to +read/write the register. For example, if wishbone width is 16 and a +register has a width of 20, we need to define two addresses, one to +access to bits 0 to 15, and one for bits 16 to 19. The total number of +needed addresses gives the minimal width of the address bus (i.e. log2(nb addr)).\\ + +The value is a initialization value. If not provided, it is 0 by +default.\\ + +Three other attributes are declared: +\begin{itemize} +\item \ot{wbAccess}: indicates if the register is written or read by + the wishbone bus. Thus, if it is written, the register is an input + of the block and if it is read, the block provides its value. +\item \ot{wbValue}: it may be a natural, a boolean, or the word + data. In the two first cases, the given value is affected to the + register as soon as the register is accessed in writing. In the + third case, the register is affected with the value that is provided + on the wishbone data bus. +\item \ot{wbDuration} : indicates if the affectation is permanent or + just a trigger. In the second case, the value is set for just one + clock cycle and then reset to the initialization value given by the + \ot{value} attribute.\\ +\end{itemize} + +A wishbone parameter is used during the generation of: +\begin{itemize} +\item the controller of the block (NB: this generation is done at the block level), +\item the entity section, because register values are in fact read/write by the block via input/output ports, +\item the component section when the owner block is used within another block. +\end{itemize} + +\section{Implementations XML description} +\label{sec:impls_xml} + +\section{Implementations class hierarchy} +\label{sec:impls_class} + + +\end{document} + + + + + diff --git a/icons/add_block.png b/icons/add_block.png new file mode 100644 index 0000000..6a12252 Binary files /dev/null and b/icons/add_block.png differ diff --git a/icons/add_block.svg b/icons/add_block.svg new file mode 100644 index 0000000..e1a8dc3 --- /dev/null +++ b/icons/add_block.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + bloc + + + diff --git a/icons/add_connection.png b/icons/add_connection.png new file mode 100644 index 0000000..cb67913 Binary files /dev/null and b/icons/add_connection.png differ diff --git a/icons/add_connection.svg b/icons/add_connection.svg new file mode 100644 index 0000000..e3e93ae --- /dev/null +++ b/icons/add_connection.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/icons/add_group.png b/icons/add_group.png new file mode 100644 index 0000000..fd3ac9e Binary files /dev/null and b/icons/add_group.png differ diff --git a/icons/add_group.svg b/icons/add_group.svg new file mode 100644 index 0000000..a0629ec --- /dev/null +++ b/icons/add_group.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + group + + + + + + + diff --git a/icons/add_group_select.png b/icons/add_group_select.png new file mode 100644 index 0000000..d1d176c Binary files /dev/null and b/icons/add_group_select.png differ diff --git a/icons/add_group_select.svg b/icons/add_group_select.svg new file mode 100644 index 0000000..06a9610 --- /dev/null +++ b/icons/add_group_select.svg @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + group + + + + + + + + diff --git a/icons/add_group_small.png b/icons/add_group_small.png new file mode 100644 index 0000000..823db63 Binary files /dev/null and b/icons/add_group_small.png differ diff --git a/icons/add_group_void.png b/icons/add_group_void.png new file mode 100644 index 0000000..9975b74 Binary files /dev/null and b/icons/add_group_void.png differ diff --git a/icons/add_group_void.svg b/icons/add_group_void.svg new file mode 100644 index 0000000..564b4d9 --- /dev/null +++ b/icons/add_group_void.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + group + + + + diff --git a/icons/copy.png b/icons/copy.png new file mode 100644 index 0000000..d7c81da Binary files /dev/null and b/icons/copy.png differ diff --git a/icons/cut.png b/icons/cut.png new file mode 100644 index 0000000..a5e87df Binary files /dev/null and b/icons/cut.png differ diff --git a/icons/delete.png b/icons/delete.png new file mode 100644 index 0000000..e421cdd Binary files /dev/null and b/icons/delete.png differ diff --git a/icons/edit_block.png b/icons/edit_block.png new file mode 100644 index 0000000..5dc6ff1 Binary files /dev/null and b/icons/edit_block.png differ diff --git a/icons/folder_add_16.png b/icons/folder_add_16.png new file mode 100644 index 0000000..213aabd Binary files /dev/null and b/icons/folder_add_16.png differ diff --git a/icons/inter_add.png b/icons/inter_add.png new file mode 100644 index 0000000..7e07d26 Binary files /dev/null and b/icons/inter_add.png differ diff --git a/icons/link.png b/icons/link.png new file mode 100644 index 0000000..0807605 Binary files /dev/null and b/icons/link.png differ diff --git a/icons/load.png b/icons/load.png new file mode 100644 index 0000000..b9fbbea Binary files /dev/null and b/icons/load.png differ diff --git a/icons/new.ico b/icons/new.ico new file mode 100644 index 0000000..041477f Binary files /dev/null and b/icons/new.ico differ diff --git a/icons/new_block.ico b/icons/new_block.ico new file mode 100644 index 0000000..7530036 Binary files /dev/null and b/icons/new_block.ico differ diff --git a/icons/new_block.png b/icons/new_block.png new file mode 100644 index 0000000..1b6973c Binary files /dev/null and b/icons/new_block.png differ diff --git a/icons/open.png b/icons/open.png new file mode 100644 index 0000000..c9802ff Binary files /dev/null and b/icons/open.png differ diff --git a/icons/paste.png b/icons/paste.png new file mode 100644 index 0000000..71f7a18 Binary files /dev/null and b/icons/paste.png differ diff --git a/icons/redo-icon.png b/icons/redo-icon.png new file mode 100644 index 0000000..4fe6c7f Binary files /dev/null and b/icons/redo-icon.png differ diff --git a/icons/save-as.png b/icons/save-as.png new file mode 100644 index 0000000..9d2f608 Binary files /dev/null and b/icons/save-as.png differ diff --git a/icons/save.png b/icons/save.png new file mode 100644 index 0000000..3d3ca4a Binary files /dev/null and b/icons/save.png differ diff --git a/icons/undo.png b/icons/undo.png new file mode 100644 index 0000000..40603ed Binary files /dev/null and b/icons/undo.png differ diff --git a/icons/window_new.png b/icons/window_new.png new file mode 100644 index 0000000..b41e50e Binary files /dev/null and b/icons/window_new.png differ diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..7449bd4 --- /dev/null +++ b/install.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +#################################### +# blast installation script +################################### + +if ! [ -f ./blast ]; then + echo "Impossible de trouver l'executable dans le répertoire courant. Arret" + exit 1 +fi +if ! [ -d ./locales ]; then + echo "Impossible de trouver les fichiers de langue dans le répertoire courant. Arret" + exit 1 +fi + +if ! [ -d /usr/local/bin ]; then + mkdir -p /usr/local/bin +fi + +if ! [ -d /usr/local/share/blast ]; then + mkdir -p /usr/local/share/blast +else + rm -rf /usr/local/share/blast + mkdir -p /usr/local/share/blast +fi + +if [ -f /usr/local/bin/blast ]; then + echo "Suppression de la version actuellement installée" + rm -f /usr/local/bin/blast +fi +echo "Installation :" +echo "binaries" +cp blast /usr/local/bin +echo "locales" +cp -r locales /usr/local/share/blast/ +echo "examples" +cp -r examples /usr/local/share/blast/ +echo "done." diff --git a/install.sh.in b/install.sh.in new file mode 100644 index 0000000..040ca55 --- /dev/null +++ b/install.sh.in @@ -0,0 +1,38 @@ +#!/bin/sh + +#################################### +# @@APPNAME@@ installation script +################################### + +if ! [ -f ./@@APPNAME@@ ]; then + echo "Impossible de trouver l'executable dans le répertoire courant. Arret" + exit 1 +fi +if ! [ -d ./locales ]; then + echo "Impossible de trouver les fichiers de langue dans le répertoire courant. Arret" + exit 1 +fi + +if ! [ -d /usr/local/bin ]; then + mkdir -p /usr/local/bin +fi + +if ! [ -d /usr/local/share/@@APPNAME@@ ]; then + mkdir -p /usr/local/share/@@APPNAME@@ +else + rm -rf /usr/local/share/@@APPNAME@@ + mkdir -p /usr/local/share/@@APPNAME@@ +fi + +if [ -f /usr/local/bin/@@APPNAME@@ ]; then + echo "Suppression de la version actuellement installée" + rm -f /usr/local/bin/@@APPNAME@@ +fi +echo "Installation :" +echo "binaries" +cp @@APPNAME@@ /usr/local/bin +echo "locales" +cp -r locales /usr/local/share/@@APPNAME@@/ +echo "examples" +cp -r examples /usr/local/share/@@APPNAME@@/ +echo "done." diff --git a/lib/README.txt b/lib/README.txt new file mode 100644 index 0000000..9ca12b8 --- /dev/null +++ b/lib/README.txt @@ -0,0 +1,119 @@ +------------------------------------ +XML description of a block model : +------------------------------------ + + attributes : + - name : required + - type : required + - value : required if context = constant/generic, optionnal if context = wb, optional but not used if context = user/port + - context : required + - core : required if context = wb, not used for others. Possibles values : r or w. Specify if the parameter will be a register + that is read by the core, i.e. an input port of the core, or written by the core. + +, attributes : + - name : required + - width : required + - purpose : optional. Possible values : clock, reset, wb, data, ... Default value is data + - level : optional. Possible values : basic, top, ... Default value is basic + - multiplicity : optional. Possible values : *, a number. Default value is 1. + + attributes : + - name : required + - width : required + - purpose : optional but forced to data + - level : optional but forced to top + - multiplicity : optional. Possible values : *, a number. Default value is 1. + If an interface has a multiplicity > 1, the user will be able to create several + instances of that interface. Their default name will be the reference name + followed by _X, where X = 1, ..., N, and N the number of instances. + + +-------------------------------------------- +XML description of an implementation model : +-------------------------------------------- + + attributes: + - ref_name: the name of an XML file that contains the block model associated to this implementation. Normally, it should be unique over all available blocks. + - ref_id : the md5 hashsum of the xml file given in ref_name. It is used to quickly retrieve the block model in the applciation. + + block: + - all elements and their attributes are amndatory but they can be void. + + block: + - used to generate the library and use instructions. + - in case of using a standard package (from work or std), only use clauses will be generated. + + block: + - constains only the architecture part of the implementation + - the name of the architecture will be determined automatically from the number of existing implementations for the block model. The name will be the name of the block followed by _X, where X is the rank of the implementation found when directories are parsed to found implementations. + +syntax: + + - @{input/output/bidir} is replaced by the "real" name in the pgrah + of blocks. It is because the reference name given in the reference + block may be changed by the user for a specific instance of that + block in the graph. Using @{name} will lead to do produce a VHDL + code with the name given by the user and not the reference name. + + - @{param} is replaced by the name of the parameter as given in the reference + blokc, which cannot be changed by the user. + + - @val{param} is replaced by the value of the parameter. This value may be + constant, given by user, or sometimes computed according to number of + instances of an interface with multiplicitiy>1. + + - @eval(expression) is replaced by the result of the evaluation of th arithmetic expression. + This expression can use +,-,*,/,(,), numbers and values of params, i.e. @val{param} expressions. + BEWARE : using a generic param value in an @eval{} is inadvisable, since it breaks the principles of + the generic use. + + - @foreach{interface} + // instructions + @endforeach + + only applicable to interfaces with multiplicity>1. Used to produce + a sequence of instruction X times, where X is the number of + interface instances created by the user. For each of those interfaces, + instructions will be generated. If ${interface} is used + within the instructions, it will be replaced by the actual evaluated interface. + + Example : let val_o an output interface with multiplicity="*" + Supposing the user created 3 instances, leaving the two first with their default name (i.e. val_o_1 val_o_2) and the last one with name val_o_last. + Then, if an implementation contains : + @foreach{val_o} + signal @{val_o}_enb : std_logic; + @endforeach + + Then the generated VHDL is : + signal val_o_1_enb : std_logic; + signal val_o_2_enb : std_logic; + signal val_o_last_enb : std_logic; + + - @caseeach{interface,signal,cases} + // instructions + @endcaseeach + + similar to foreach but to produce a case statement. signal is the + signal used to test against the cases. Obviously, there should be + as much cases as the number of interface instances. If not, the + generation will not be complete. + cases may be a predefined variables (see below) or a list of values. + + Example : with the same assumptions as in foreach example, + + @caseeach(val_o,sel_s,@#:1) + @{val_o}_enb <= '1'; + @endcaseeach + + will produce + case sel_s is + when 1 => val_o_1_enb <= '1'; + when 2 => val_o_2_enb <= '1'; + when 3 => val_o_last_enb <= '1'; + end case; + + - @#[-]:number : only usefull within foreach, caseeach, ... Produces an output + that starts at number and increments or decrements (with #-) at each case. + + Example : @#-:3 will produce 3, 2, 1, 0, -1, ... + diff --git a/lib/implementations/apf27-wb-master_impl.xml b/lib/implementations/apf27-wb-master_impl.xml new file mode 100644 index 0000000..7970abf --- /dev/null +++ b/lib/implementations/apf27-wb-master_impl.xml @@ -0,0 +1,69 @@ + + + + + + + + This component is an interface between i.MX signals + and the interconnector component. + + + On i.MX<->FPGA connection : the WEIM part of i.MX has a 16 bits bus address + but only [1:12] bits are connected to FPGA pins. From the i.MX point of view + it means that reading in memory mapped address 0x0002 or 0x0003 gives the same + result since the LSB bit of the address is not transmited. + + These 12 bits are forwarded to the interconnector which is responsible to + determine for what IP the data and addr signals must be routed. + + + + + + + + + + + + + + signal write : std_logic; + signal read : std_logic; + signal strobe : std_logic; + signal writedata : std_logic_vector(@{wb_data_width}-1 downto 0); + signal address : std_logic_vector(@{wb_addr_width}-1 downto 0); + +begin + +-- ---------------------------------------------------------------------------- +-- External signals synchronization process +-- ---------------------------------------------------------------------------- + process(@{clk}, @{reset}) + begin + if(@{reset}='1') then + write <= '0'; + read <= '0'; + strobe <= '0'; + writedata <= (others => '0'); + address <= (others => '0'); + elsif(rising_edge(@{clk})) then + strobe <= not (@{imx_cs_n}) and not(@{imx_oe_n} and @{imx_eb3_n}); + write <= not (@{imx_cs_n} or @{imx_eb3_n}); + read <= not (@{imx_cs_n} or @{imx_oe_n}); + address <= @{imx_addr}; + writedata <= @{imx_data}; + end if; + end process; + + @{addr_o} <= address when (strobe = '1') else (others => '0'); + @{dat_o} <= writedata when (write = '1') else (others => '0'); + @{stb_o} <= strobe; + @{we_o} <= write; + @{cyc_o} <= strobe; + + @{imx_data} <= @{dat_i} when(read = '1' ) else (others => 'Z'); + + + diff --git a/lib/implementations/demux_impl.xml b/lib/implementations/demux_impl.xml new file mode 100644 index 0000000..bcb7ea8 --- /dev/null +++ b/lib/implementations/demux_impl.xml @@ -0,0 +1,71 @@ + + + + + + + + This component is a synchronous demultiplixer with variable number of outputs + + + No notes + + + + + + + + + + + + + signal sel_s : unsigned(@eval{@val{sel_width}-1} downto 0); + signal val_i_dly : std_logic_vector(@eval{@val{val_width}-1} downto 0}; + + @foreach{val_o} + signal @{val_o}_enb : std_logic; + @endforeach + + begin + + sel_s <= @{sel_i}; + + delay_input : process(@{clk}, @{rst}) + begin + if(@{rst}='1') then + val_i_dly <= (others => '0'); + elsif(rising_edge(@{clk})) then + val_i_dly <= @{val_i}; + end if; + end process delay_input; + + + demux : process(@{clk}, @{rst}) + begin + if(@{rst}='1') then + + @foreach{val_o} + @{val_o}_enb <= '0'; + @endforeach + + elsif(rising_edge(@{clk})) then + + @foreach{val_o} + @{val_o}_enb <= '0'; + @endforeach + + @caseeach{val_o,sel_s,@#:1} + @{val_o}_enb <= '1'; + @endcaseeach + + end if; + end process demux; + + @foreach{val_o} + @{val_o} <= val_i_dly when (@{val_o}_enb = '1') else (others => '0'); + @endforeach + + + diff --git a/lib/implementations/impls.bmf b/lib/implementations/impls.bmf new file mode 100644 index 0000000..b544d25 Binary files /dev/null and b/lib/implementations/impls.bmf differ diff --git a/lib/implementations/multadd.vhd b/lib/implementations/multadd.vhd new file mode 100644 index 0000000..394b223 --- /dev/null +++ b/lib/implementations/multadd.vhd @@ -0,0 +1,76 @@ +------------------------------------------------------------------------------- +-- +-- File : multadd.vhd +-- Related files : +-- +-- Author(s) : stephane Domas (sdomas@univ-fcomte.fr) +-- +-- Creation Date : 2015/04/27 +-- +-- Description : This component is a multadd +-- +-- Note : No notes +-- +------------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity multadd is + generic ( + wb_data_width : integer := 16; + wb_addr_width : integer := 12 + ); + port ( + -- clk/rst from multadd wrapper + rst : in std_logic; + clk : in std_logic; + + -- registers r/w via wishbone + wb_do_op : in std_logic; + wb_c : in std_logic_vector(wb_data_width-1 downto 0); + wb_d : out std_logic_vector(2*wb_data_width-1 downto 0); + + -- data ports + val1_i : in std_logic_vector(17 downto 0); + val2_i : in std_logic_vector(17 downto 0); + res_o : out std_logic_vector(35 downto 0) + ); +end multadd; + + +architecture multadd_1 of multadd is + + -- Signals + signal a_s : signed(17 downto 0); + signal b_s : signed(17 downto 0); + signal c_s : signed(35 downto 0); + signal result : signed(35 downto 0); + +begin + + a_s <= signed(val1_i); + b_s <= signed(val2_i); + c_s <= resize(signed(wb_c), 36); + + do_mult_process : process (clk, rst) + begin + if rst = '1' then + + result <= to_signed(0, 36); + + elsif (rising_edge(clk)) then + + if wb_do_op = '1' then + result <= a_s * b_s + c_s; + end if; + + end if; + end process do_mult_process; + + res_o <= std_logic_vector(result); + wb_d <= std_logic_vector(resize(result, 2*wb_data_width)); + +end multadd_1; + diff --git a/lib/implementations/multadd_core.vhd b/lib/implementations/multadd_core.vhd new file mode 100644 index 0000000..0f42489 --- /dev/null +++ b/lib/implementations/multadd_core.vhd @@ -0,0 +1,76 @@ +------------------------------------------------------------------------------- +-- +-- File : multadd_core.vhd +-- Related files : +-- +-- Author(s) : stephane Domas (sdomas@univ-fcomte.fr) +-- +-- Creation Date : 2015/04/27 +-- +-- Description : This component is a multadd +-- +-- Note : No notes +-- +------------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity multadd_core is + generic ( + wb_data_width : integer := 16; + wb_addr_width : integer := 12 + ); + port ( + -- clk/rst from multadd wrapper + rst : in std_logic; + clk : in std_logic; + + -- registers r/w via wishbone + wb_do_op : in std_logic; + wb_c : in std_logic_vector(wb_data_width-1 downto 0); + wb_d : out std_logic_vector(2*wb_data_width-1 downto 0); + + -- data ports + val1_i : in std_logic_vector(17 downto 0); + val2_i : in std_logic_vector(17 downto 0); + res_o : out std_logic_vector(35 downto 0) + ); +end multadd_core; + + +architecture multadd_core_1 of multadd_core is + + -- Signals + signal a_s : signed(17 downto 0); + signal b_s : signed(17 downto 0); + signal c_s : signed(35 downto 0); + signal result : signed(35 downto 0); + +begin + + a_s <= signed(val1_i); + b_s <= signed(val2_i); + c_s <= resize(signed(wb_c),36); + + do_mult_process : process (clk, rst) + begin + if rst = '1' then + + result <= to_signed(0,36); + + elsif (rising_edge(clk)) then + + if wb_do_op = '1' then + result <= a_s * b_s + c_s; + end if; + + end if; + end process do_mult_process; + + res_o <= std_logic_vector(result); + wb_d <= std_logic_vector(resize(result,32); + +end multadd_core_1; + diff --git a/lib/implementations/multadd_ctrl.vhd b/lib/implementations/multadd_ctrl.vhd new file mode 100644 index 0000000..b02bd3d --- /dev/null +++ b/lib/implementations/multadd_ctrl.vhd @@ -0,0 +1,154 @@ +------------------------------------------------------------------------------- +-- +-- File : multadd_ctrl.vhd +-- Related files : multadd.vhd +-- +-- Author(s) : stephane Domas (sdomas@univ-fcomte.fr) +-- +-- Creation Date : 2015/04/27 +-- +-- Description : This component is generated automatically. +-- It contains processes to r/w registers defined for multadd +-- via wishbone. +-- +-- Note : No notes +-- +------------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +------------------------------------------------------------------------------- +-- wishbone registers +------------------------------------------------------------------------------- +-- name bits address R/W +-- wb_do_op 0 0x0000 W +-- wb_c (15 downto 0) 0x0001 W +-- wb_d (15 downto 0) 0x0002 R +-- wb_d (31 downto 0) 0x0003 R +-- +------------------------------------------------------------------------------- + +entity multadd_ctrl is + generic ( + wb_data_width : integer := 16; + wb_addr_width : integer := 2 + ); + port ( + -- clk/rst from interconnector + rst : in std_logic; + clk : in std_logic; + + -- addr/data from interconnector + addr_i : in std_logic_vector(wb_addr_width-1 downto 0); + dat_i : in std_logic_vector(wb_data_width-1 downto 0); + dat_o : out std_logic_vector(wb_data_width-1 downto 0); + cyc_i : in std_logic; + stb_i : in std_logic; + we_i : in std_logic; + ack_o : out std_logic; + + -- registers r/w via wishbone that are forwarded to the block + wb_do_op : out std_logic; + wb_c : out std_logic_vector(wb_data_width-1 downto 0); + wb_d : in std_logic_vector(2*wb_data_width-1 downto 0) + + ); +end multadd_ctrl; + + +architecture multadd_ctrl1 of multadd_ctrl is + + -- signals : registers r/w via wishbone + signal wb_do_op_s : std_logic; + signal wb_c_s : std_logic_vector(wb_data_width-1 downto 0); + signal wb_d_s : std_logic_vector(2*wb_data_width-1 downto 0); + + -- signals : wishbone related + signal read_data : std_logic_vector(wb_data_width-1 downto 0); + signal read_ack : std_logic; + signal write_ack : std_logic; + signal write_rise : std_logic; + +begin +-- ---------------------------------------------------------------------------- +-- signals from/to ports +-- ---------------------------------------------------------------------------- + wb_d_s <= wb_d; + wb_c <= wb_c_s; + wb_do_op <= wb_do_op_s; + +-- ---------------------------------------------------------------------------- +-- write rising edge detection +-- ---------------------------------------------------------------------------- + detection_front : process(gls_clk, gls_reset) + variable signal_old : std_logic; + begin + if (gls_reset = '1') then + signal_old := '0'; + write_rise <= '0'; + elsif rising_edge(gls_clk) then + if (signal_old = '0' and stb_i = '1' and cyc_i = '1' and we_i = '1') then + write_rise <= '1'; + else + write_rise <= '0'; + end if; + signal_old := we_i; + end if; + end process detection_front; + +-- ---------------------------------------------------------------------------- +-- Register reading process +-- ---------------------------------------------------------------------------- + reading_reg : process(clk, rst) + begin + if(rst = '1') then + read_ack <= '0'; + read_data <= (others => '0'); + elsif(rising_edge(clk)) then + read_ack <= '0'; + if (stb_i = '1' and cyc_i = '1' and we_i = '0') then + read_ack <= '1'; + if(addr_i = "10") then + read_data <= wb_d_s(15 downto 0); + elsif(addr_i = "11") then + read_data <= wb_d_s(31 downto 16); + else + read_data <= (others => '0'); + end if; + end if; + end if; + end process reading_reg; + +-- ---------------------------------------------------------------------------- +-- Register writing process +-- ---------------------------------------------------------------------------- + writing_reg : process(clk, rst) + begin + if(rst = '1') then + write_ack <= '0'; + wb_do_op_s <= '0'; + wb_c_s <= (others => '0'); + elsif(rising_edge(clk)) then + write_ack <= '0'; + wb_do_op_s <= '0'; + if (write_rise = '1') then + write_ack <= '1'; + if (addr_i = "00") then + wb_do_op_s <= '1'; + elsif (addr_i = "01") then + wb_c_s <= dat_i; + end if; + end if; + end if; + end process writing_reg; + +-- ---------------------------------------------------------------------------- +-- assignations for wishbone outputs +-- ---------------------------------------------------------------------------- + ack_o <= read_ack or write_ack; + dat_o <= read_data when (stb_i = '1' and cyc_i = '1' and we_i = '0') else (others => '0'); + +end multadd_ctrl1; + diff --git a/lib/implementations/multadd_impl.xml b/lib/implementations/multadd_impl.xml new file mode 100644 index 0000000..fc2d10f --- /dev/null +++ b/lib/implementations/multadd_impl.xml @@ -0,0 +1,63 @@ + + + + + + + + This component is a multadd + + + No notes + + + + + + + + + + + + + -- Signals + signal a_s : signed(@eval{@val{in_width}-1} downto 0); + signal b_s : signed(@eval{@val{in_width}-1} downto 0); + signal c_s : signed(@eval{2*@val{in_width}-1} downto 0); + signal result : signed(@eval{2*@val{in_width}-1} downto 0); + +begin + + a_s <= signed(@{a}); + b_s <= signed(@{b}); + c_s <= resize(signed(@{wb_c}),@eval{2*@val{in_width}}); + + do_mult_process : process (@{clk}, @{rst}) + begin + if @{rst} = '1' then + + result <= to_signed(0,@eval{2*@val{in_width}); + + elsif (rising_edge(@{clk})) then + + if @{wb_do_op} = '1' then + result <= a_s * b_s + c_s; + end if; + + end if; + end process do_mult_process; + + @{d} <= std_logic_vector(result); + @{wb_d} <= std_logic_vector(resize(result,2*wb_data_width)); + + + + + + + + + + + diff --git a/lib/references/apf27-wb-master.xml b/lib/references/apf27-wb-master.xml new file mode 100644 index 0000000..82ee08a --- /dev/null +++ b/lib/references/apf27-wb-master.xml @@ -0,0 +1,46 @@ + + + + + wishbone master for apf27 + + + + + This block is the wishbone master of the design, connected to the i.MX of APF27 + + + This block is the wishbone master of the design, connected to the i.MX of APF27 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/references/demux.xml b/lib/references/demux.xml new file mode 100644 index 0000000..cd66442 --- /dev/null +++ b/lib/references/demux.xml @@ -0,0 +1,36 @@ + + + + + block demultiplexer + + + + + This block demux an entry presented on FPGA pins over a variable number of outputs + + + This block demux an entry presented on FPGA pins over a variable number of outputs + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/references/multadd.xml b/lib/references/multadd.xml new file mode 100644 index 0000000..7ef16bd --- /dev/null +++ b/lib/references/multadd.xml @@ -0,0 +1,43 @@ + + + + + block multiply/add + + + + + This block multiplies 2 input values, adding the result to a third one. + + + This block does d=a*b+c. + a/b are provided by input port. + c is set via the wishbone interconnector + d is forwarded to an output port and can be retrieved via the wishbone interconnector + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/references/references.bmf b/lib/references/references.bmf new file mode 100644 index 0000000..6685627 Binary files /dev/null and b/lib/references/references.bmf differ diff --git a/object-files.txt b/object-files.txt new file mode 100644 index 0000000..841a369 --- /dev/null +++ b/object-files.txt @@ -0,0 +1,47 @@ +COMMON-OBJ = $(BUILDPATH)/AbstractBlock.o \ + $(BUILDPATH)/FunctionalBlock.o \ + $(BUILDPATH)/ReferenceBlock.o \ + $(BUILDPATH)/GroupBlock.o \ + $(BUILDPATH)/AbstractInterface.o \ + $(BUILDPATH)/ConnectedInterface.o \ + $(BUILDPATH)/FunctionalInterface.o \ + $(BUILDPATH)/GroupInterface.o \ + $(BUILDPATH)/ReferenceInterface.o \ + $(BUILDPATH)/BlockImplementation.o \ + $(BUILDPATH)/Graph.o \ + $(BUILDPATH)/AbstractBoxItem.o \ + $(BUILDPATH)/BoxItem.o \ + $(BUILDPATH)/GroupItem.o \ + $(BUILDPATH)/BlockCategory.o \ + $(BUILDPATH)/BlockLibraryTree.o \ + $(BUILDPATH)/BlockLibraryWidget.o \ + $(BUILDPATH)/moc_BlockLibraryWidget.o \ + $(BUILDPATH)/BlockParameter.o \ + $(BUILDPATH)/BlockParameterUser.o \ + $(BUILDPATH)/BlockParameterGeneric.o \ + $(BUILDPATH)/BlockParameterPort.o \ + $(BUILDPATH)/BlockParameterWishbone.o \ + $(BUILDPATH)/ConnectionItem.o \ + $(BUILDPATH)/Dispatcher.o \ + $(BUILDPATH)/Exception.o \ + $(BUILDPATH)/Graph.o \ + $(BUILDPATH)/GroupScene.o \ + $(BUILDPATH)/InterfaceItem.o \ + $(BUILDPATH)/MainWindow.o \ + $(BUILDPATH)/moc_MainWindow.o \ + $(BUILDPATH)/ArithmeticEvaluator.o \ + $(BUILDPATH)/moc_ArithmeticEvaluator.o \ + $(BUILDPATH)/BlockWidget.o \ + $(BUILDPATH)/moc_BlockWidget.o \ + $(BUILDPATH)/GroupWidget.o \ + $(BUILDPATH)/moc_GroupWidget.o \ + $(BUILDPATH)/Parameters.o \ + $(BUILDPATH)/moc_Parameters.o \ + $(BUILDPATH)/rcc_blast.o \ + $(BUILDPATH)/BlocksToConfigureWidget.o \ + $(BUILDPATH)/moc_BlocksToConfigureWidget.o \ + $(BUILDPATH)/ParametersWindow.o \ + $(BUILDPATH)/moc_ParametersWindow.o \ + $(BUILDPATH)/InterfacePropertiesWindow.o \ + $(BUILDPATH)/moc_InterfacePropertiesWindow.o \ + $(BUILDPATH)/blast.o diff --git a/projectfile.xsd b/projectfile.xsd new file mode 100644 index 0000000..36fe54e --- /dev/null +++ b/projectfile.xsd @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/save/sauv.xml b/save/sauv.xml new file mode 100644 index 0000000..2493342 --- /dev/null +++ b/save/sauv.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/save/test.xml b/save/test.xml new file mode 100644 index 0000000..ac40f85 --- /dev/null +++ b/save/test.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testproject.xml b/testproject.xml new file mode 100644 index 0000000..f482cfd --- /dev/null +++ b/testproject.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +