]> AND Private Git Repository - blast.git/blob - InterfaceItem.cpp
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
552e15989b990aa9257d362333c66ccfe4cefc9e
[blast.git] / InterfaceItem.cpp
1 #include "InterfaceItem.h"
2
3 #include "Parameters.h"
4 #include "GroupInterface.h"
5 #include "FunctionalInterface.h"
6 #include "BoxItem.h"
7
8 int InterfaceItem::counter = 0;
9
10 InterfaceItem::InterfaceItem(double _position,
11                              int _orientation,
12                              ConnectedInterface *_refInter,
13                              AbstractBoxItem* _owner,
14                              Parameters* _params){
15   positionRatio = _position;
16   orientation = _orientation;
17   refInter = _refInter;
18
19   // CAUTION : the owner must add explicitely this item to its interface, calling addInterface()
20   owner = _owner;
21   params = _params;
22   selected = false;
23   name = refInter->getName();
24   QFontMetrics fmName(params->defaultIfaceFont);
25   nameWidth = fmName.width(name);
26   nameHeight = fmName.height();
27   // by default, only data interface are visible
28   if (refInter->getPurpose() == AbstractInterface::Data) {
29     visible = true;
30   }
31   else {
32     visible = false;
33   }
34
35   this->id = InterfaceItem::counter++;
36
37   updatePosition();
38 }
39
40
41 InterfaceItem::InterfaceItem(){
42   this->id = counter++;
43 }
44
45 /* boundingRect() : give the bounding rect in the blockitem coord. system */
46 QRectF InterfaceItem::boundingRect() const {
47
48   QPointF pointHG;
49   QSizeF s;
50
51   switch(orientation){
52   case Parameters::East :
53     pointHG = QPointF(originPoint.x(),originPoint.y()-(params->arrowHeight/2.0));
54     s = QSizeF(params->arrowWidth+params->arrowLineLength, params->arrowHeight);
55     break;
56   case Parameters::North :
57     pointHG = QPointF(originPoint.x()-(params->arrowHeight/2.0),originPoint.y()-params->arrowWidth-params->arrowLineLength);
58     s = QSizeF(params->arrowHeight,params->arrowWidth+params->arrowLineLength);
59     break;
60   case Parameters::West :
61     pointHG = QPointF(originPoint.x()-params->arrowLineLength-params->arrowWidth,originPoint.y()-(params->arrowHeight/2.0));
62     s = QSizeF(params->arrowWidth+params->arrowLineLength, params->arrowHeight);
63     break;
64   case Parameters::South :
65     pointHG = QPointF(originPoint.x()-(params->arrowHeight/2.0),originPoint.y());
66     s = QSizeF(params->arrowHeight, params->arrowWidth+params->arrowLineLength);
67     break;
68   default :
69     pointHG = QPointF();
70     s = QSizeF();
71     break;
72   }  
73
74   return QRectF(pointHG,s);
75 }
76
77 void InterfaceItem::paint(QPainter *painter) {
78
79   if(visible) {
80
81     painter->save();
82
83     if(selected) {
84       painter->setPen(QPen(Qt::red,2));
85     }
86     else if(refInter->getLevel() == AbstractInterface::Basic) {
87       painter->setPen(QPen(Qt::darkCyan,1));
88     }
89     else if(refInter->getLevel() == AbstractInterface::Top) {
90       painter->setPen(QPen(Qt::black,1));
91     }
92
93     painter->translate(originPoint);
94
95     switch(orientation) {
96     case Parameters::North:
97       painter->rotate(-90);
98       break;
99     case Parameters::West:
100       painter->rotate(180);
101       break;
102     case Parameters::South:
103       painter->rotate(90);
104       break;
105     }
106
107     // draw arrows
108     if(refInter->getDirection() == AbstractInterface::Input) {
109       painter->drawPath(params->inArrow);
110     }
111     else if(refInter->getDirection() == AbstractInterface::Output) {
112       painter->drawPath(params->outArrow);
113     } else if(refInter->getDirection() == AbstractInterface::InOut) {
114       painter->drawPath(params->inArrow);
115       painter->drawPath(params->outArrow);
116     }
117
118     // draw names
119
120     // reset to normal if at west
121     if(orientation == Parameters::West){
122       painter->rotate(180);
123     }
124
125     painter->setFont(params->defaultIfaceFont);
126
127     QFontMetrics fm = painter->fontMetrics();
128     int w = nameWidth + owner->getIfaceMargin();
129     int h = nameHeight;
130
131     if(orientation == Parameters::West){
132
133       if(owner->isGroupItem()){
134         painter->drawText(-(w+params->arrowWidth+params->arrowLineLength),-h/2,w,h,Qt::AlignLeft | Qt::TextWordWrap, refInter->getName());
135       }
136       else if(owner->isBoxItem()){
137         painter->drawText(0,-h/2,w,h,Qt::AlignRight | Qt::TextWordWrap, refInter->getName());
138       }
139     }
140     else  {
141
142       if(owner->isGroupItem()) {
143         painter->drawText(params->arrowWidth+params->arrowLineLength,-h/2,w,h,Qt::AlignRight | Qt::TextWordWrap, refInter->getName());
144       }
145       else if(owner->isBoxItem()) {
146         painter->drawText(-w,-h/2,w,h,Qt::AlignLeft | Qt::TextWordWrap, refInter->getName());
147       }
148     }    
149
150     painter->restore();
151   }
152 }
153
154 QPointF InterfaceItem::getEndPointInGroup() {
155   QPointF p;
156
157   if (owner->isGroupItem()) {
158     p = originPoint;
159   }
160   else {
161     double x = owner->x() + originPoint.x();
162     double y = owner->y() + originPoint.y();
163     switch(orientation){
164     case Parameters::East:
165       x += params->arrowWidth+params->arrowLineLength;
166       break;
167     case Parameters::North:
168       y -= params->arrowWidth+params->arrowLineLength;
169       break;
170     case Parameters::West:
171       x -= params->arrowWidth+params->arrowLineLength;
172       break;
173     case Parameters::South:
174       y += params->arrowWidth+params->arrowLineLength;
175       break;
176     }
177     p = QPointF(x,y);
178   }
179
180   //cout << "iface end point in group item: " << p.x() << "," << p.y() << endl;
181   return p;
182 }
183
184 void InterfaceItem::setOriginPoint() {
185   switch(orientation){
186   case Parameters::East:
187     originPoint = QPointF(owner->getWidth(),position);
188     break;
189   case Parameters::North:
190     originPoint = QPointF(position,0);
191     break;
192   case Parameters::West:
193     originPoint = QPointF(0,position);
194     break;
195   case Parameters::South:
196     originPoint = QPointF(position,owner->getHeight());
197     break;
198   }
199 }
200
201 QString InterfaceItem::getStrOrientation() {
202   QString str = NULL;
203   switch(orientation){
204   case Parameters::North :
205     str = QString("north");
206     break;
207   case Parameters::South :
208     str = QString("south");
209     break;
210   case Parameters::East :
211     str = QString("east");
212     break;
213   case Parameters::West :
214     str = QString("west");
215     break;
216   }
217
218   return str;
219 }
220
221 int InterfaceItem::getIntOrientation(QString str) {
222   if(str == "west") return Parameters::West;
223   if(str == "east") return Parameters::East;
224   if(str == "south") return Parameters::South;
225   if(str == "north") return Parameters::North;
226   return -1;
227 }
228
229
230 /* connectWith() :
231   - modify all necessary attributes in the model to create a connection
232   between current InterfaceItem and iface. Note that the source and destination
233   are deduced from the direction (In, Out) and the type of the owner (funcitonal, group)
234
235   CAUTION: No security checks are done. This method must be called only if canConnectWith has been called and returned true.
236
237   NOTE : conditions so that this InterfaceItem can be connected with inter.
238      (i.e. current one can connect to inter OR inter can connect to current)
239
240      Here are all the possible combinations, depending on the type of the
241      block/item and direction of the interface, which are :
242      GI/GB : a GroupItem referencing a GroupBlock (single solution for GI)
243      BI/FB : a BlockItem referencing a FunctionalBlock
244      BI/GB : a BlockItem referencing a GroupBlock
245
246      For GI/GB:
247      - Input can connect with BI/FB or BI/GB Input
248      - Output can connect with BI/FB or BI/GB Output
249
250      For BI/FB:
251      - Input can connect with:
252          GI/GB Input
253          BI/FB Output
254          BI/GB Output
255      - Output can connect with:
256          GI/GB Output
257          BI/FB Input
258          BI/GB Input
259
260      For BI/GB:
261      - Input can connect with:
262          GI/GB Input
263          BI/FB Output
264          BI/GB Output
265      - Output can connect with:
266          GI/GB Output
267          BI/FB Input
268          BI/GB Input
269
270     And whatever the case an InOut can only connect with an InOut
271     We note that:
272        - the IG does not allow the connect a GI/GB interface to an
273        interface of another GI/GB, thus the case is not considered above.
274        - BI/FB and BI/GB are the same.
275        - the cases where direction are the same only occur when
276        the 2 items are of different type (GI and BI)
277        - the cases where directions are different only occur when
278        the 2 are of both BlockItem
279
280 */
281 bool InterfaceItem::connectWith(InterfaceItem *iface) {
282   ConnectedInterface* interThis = refInter; // the reference of this
283   ConnectedInterface* interOther = iface->refInter; // the reference of the other
284   ConnectedInterface* src = NULL, *dest = NULL;
285
286   if(interThis->getDirection() == AbstractInterface::InOut && interOther->getDirection() == AbstractInterface::InOut){
287     /* NOTE: InOut interfaces have both directions and thus are
288        connected from inter1 to inter2 AND inter2 to inter1
289        Another effect is that a InOut can be connected to/from a single
290        InOut.
291     */
292     if((interThis->getConnectedFrom() == NULL) && (interOther->getConnectedFrom() == NULL)) {
293
294       interOther->connectFrom(interThis);
295       interOther->getConnectedTo().append(interThis);
296       interThis->connectFrom(interOther);
297       interThis->getConnectedTo().append(interOther);
298
299       cout << "connecting 2 InOut"<< endl;
300       return true;
301     }
302     return false;
303   }
304   else if (interThis->getDirection() == interOther->getDirection()) {
305
306     // cannot connect  GI to GI or 2 BI of the same direction.
307     if ((getOwner()->isGroupItem()) && (iface->getOwner()->isGroupItem())) return false;
308     if ((getOwner()->isBoxItem()) && (iface->getOwner()->isBoxItem())) return false;
309
310     if (interThis->getDirection() == AbstractInterface::Input) { // both are inputs
311       cout << "connecting GI to BI" << endl;
312       if(getOwner()->isGroupItem()) {
313         src = interThis;
314         dest = interOther;
315       }
316       else {
317         src = interOther;
318         dest = interThis;
319       }
320     }
321     else { // both are outputs
322       cout << "connecting BO to GO" << endl;
323       if(getOwner()->isGroupItem()){
324         src = interOther;
325         dest = interThis;
326       }
327       else {
328         src = interThis;
329         dest = interOther;
330       }
331     }
332   }
333   else {
334     if ((getOwner()->isGroupItem()) || (iface->getOwner()->isGroupItem())) return false;
335
336     cout << "connecting BO to BI" << endl;
337     if(interOther->getDirection() == AbstractInterface::Output) {
338       src = interOther;
339       dest = interThis;
340     }
341     else {
342       src = interThis;
343       dest = interOther;
344     }
345   }
346
347   if(dest != NULL && src != NULL){
348     // cannot overrive existing connectionFrom
349     if(dest->getConnectedFrom() == NULL) {
350       dest->connectFrom(src);
351       src->connectTo(dest);
352       return true;
353     }
354     else {
355       return false;
356     }
357   }
358   return false;
359 }
360
361 void InterfaceItem::unconnectTo(InterfaceItem *iface)
362 {
363   if(iface->refInter->getConnectedFrom() == refInter){
364     iface->refInter->connectFrom(NULL);
365   }
366   if(iface->refInter->getConnectedTo().contains(refInter)){
367     cout << "abnormal case while removing iface conn from " << qPrintable(name) << " to " << qPrintable(iface->name) << endl;
368     iface->refInter->removeConnectedTo(refInter);
369   }
370   if(refInter->getConnectedFrom() == iface->refInter) {
371     cout << "abnormal case while removing iface conn from " << qPrintable(name) << " to " << qPrintable(iface->name) << endl;
372     refInter->connectFrom(NULL);
373   }
374   if(refInter->getConnectedTo().contains(iface->refInter)){
375     refInter->removeConnectedTo(iface->refInter);
376   }
377 }
378
379 void InterfaceItem::updatePosition()
380 {
381   if(orientation == Parameters::North || orientation == Parameters::South){
382     position = positionRatio * owner->getWidth();
383   } else {
384     position = positionRatio * owner->getHeight();
385   }
386   setOriginPoint();
387 }
388
389 void InterfaceItem::addConnectionItem(ConnectionItem* item) {
390   connections.append(item);
391 }
392
393 void InterfaceItem::removeConnectionItem(ConnectionItem* item) {
394   connections.removeOne(item);
395 }
396
397 QDataStream &operator <<(QDataStream &out, InterfaceItem *i) {
398
399 #ifdef DEBUG_INCLFUN
400   out.setVersion(QDataStream::Qt_5);
401
402   QByteArray interfaceData;
403   QDataStream toWrite(&interfaceData, QIODevice::WriteOnly);
404
405   toWrite << i->getId();
406   toWrite << i->getName();
407   toWrite << i->getPositionRatio();
408   toWrite << i->getOrientation();
409
410   foreach(QGraphicsItem* item, i->params->getCurrentScene()->items()){
411     if(item->data(0) == "connection"){
412       ConnectionItem *conn = dynamic_cast<ConnectionItem*>(item);
413       if(conn->getFromInterfaceItem() == i || conn->getToInterfaceItem() == i){
414         toWrite << conn->getId();
415         cout << "id connection : " << conn->getId() << endl;
416       }
417     }
418   }
419   out << interfaceData;
420 #endif
421   return out;
422 }
423
424 QDataStream &operator >>(QDataStream &in, InterfaceItem &i) {
425
426 #ifdef DEBUG_INCLFUN
427   in.setVersion(QDataStream::Qt_5);
428
429   int id, orientation;
430   double positionRatio;
431   QString name;
432
433   in >> id;
434   in >> name;
435   in >> positionRatio;
436   in >> orientation;
437
438   i.setId(id);
439   i.setName(name);
440   i.setPositionRatio(positionRatio);
441   i.setOrientation(orientation);
442   i.updatePosition();
443 #endif
444   return in;
445 }