1 /*******************************************************************
2 
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5 
6 Fritzing is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 Fritzing is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
18 
19 ********************************************************************
20 
21 $Revision: 7000 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-29 07:24:08 +0200 (Mo, 29. Apr 2013) $
24 
25 ********************************************************************/
26 
27 /*
28 
29 curvy To Do
30 
31 	curvy to begin with? would have to vary with some function of angle and distance
32 		could convert control points to t values?
33 
34 	turn curvature on/off per view
35 
36 ---------------------------------------------------------
37 
38 later:
39 
40 	clippable wire
41 
42 	gerber
43 
44 	autorouter warning in PCB view
45 
46 	modify parameters (tension, unit area)?
47 
48 */
49 
50 /////////////////////////////////////////////////////////////////
51 
52 #include "wire.h"
53 
54 #include <QLineF>
55 #include <QPen>
56 #include <QRadialGradient>
57 #include <QBrush>
58 #include <QPen>
59 #include <QGraphicsScene>
60 #include <QList>
61 #include <QGraphicsItem>
62 #include <QSet>
63 #include <QComboBox>
64 #include <QToolTip>
65 #include <QApplication>
66 #include <QCheckBox>
67 #include <QHBoxLayout>
68 
69 #include "../debugdialog.h"
70 #include "../sketch/infographicsview.h"
71 #include "../connectors/connectoritem.h"
72 #include "../connectors/svgidlayer.h"
73 #include "../fsvgrenderer.h"
74 #include "partlabel.h"
75 #include "../model/modelpart.h"
76 #include "../utils/graphicsutils.h"
77 #include "../utils/textutils.h"
78 #include "../utils/bezier.h"
79 #include "../utils/bezierdisplay.h"
80 #include "../utils/cursormaster.h"
81 #include "../utils/ratsnestcolors.h"
82 #include "../layerattributes.h"
83 
84 #include <stdlib.h>
85 
86 QVector<qreal> Wire::TheDash;
87 QVector<qreal> RatDash;
88 QBrush BandedBrush(QColor(255, 255, 255));
89 
90 
91 QHash<QString, QString> Wire::colorTrans;
92 QStringList Wire::colorNames;
93 QHash<int, QString> Wire::widthTrans;
94 QList<int> Wire::widths;
95 double Wire::STANDARD_TRACE_WIDTH;
96 double Wire::HALF_STANDARD_TRACE_WIDTH;
97 double Wire::THIN_TRACE_WIDTH;
98 
99 const double DefaultHoverStrokeWidth = 4;
100 
101 static Bezier UndoBezier;
102 static BezierDisplay * TheBezierDisplay = NULL;
103 
104 ////////////////////////////////////////////////////////////
105 
alphaLessThan(QColor * c1,QColor * c2)106 bool alphaLessThan(QColor * c1, QColor * c2)
107 {
108 	return c1->alpha() < c2->alpha();
109 }
110 
debugCompare(ItemBase * it)111 void debugCompare(ItemBase * it) {
112     Wire * wire = dynamic_cast<Wire *>(it);
113     if (wire) {
114         QRectF r0 = wire->connector0()->rect();
115         QRectF r1 = wire->connector1()->rect();
116         if (qAbs(r0.left() - r1.left()) < 0.1 &&
117             qAbs(r0.right() - r1.right()) < 0.1 &&
118             qAbs(r0.top() - r1.top()) < 0.1 &&
119             qAbs(r0.bottom() - r1.bottom()) < 0.1)
120         {
121             wire->debugInfo("zero wire");
122             if (wire->viewID() == ViewLayer::PCBView) {
123                 DebugDialog::debug("in pcb");
124             }
125         }
126     }
127 }
128 
129 /////////////////////////////////////////////////////////////
130 
WireAction(QAction * action)131 WireAction::WireAction(QAction * action) : QAction(action) {
132 	m_wire = NULL;
133 	this->setText(action->text());
134 	this->setStatusTip(action->statusTip());
135 	this->setCheckable(action->isCheckable());
136 }
137 
WireAction(const QString & title,QObject * parent)138 WireAction::WireAction(const QString & title, QObject * parent) : QAction(title, parent) {
139 	m_wire = NULL;
140 }
141 
setWire(Wire * w)142 void WireAction::setWire(Wire * w) {
143 	m_wire = w;
144 }
145 
wire()146 Wire * WireAction::wire() {
147 	return m_wire;
148 }
149 
150 /////////////////////////////////////////////////////////////
151 
Wire(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu,bool initLabel)152 Wire::Wire( ModelPart * modelPart, ViewLayer::ViewID viewID,  const ViewGeometry & viewGeometry, long id, QMenu* itemMenu, bool initLabel)
153 	: ItemBase(modelPart, viewID, viewGeometry, id, itemMenu)
154 {
155     m_banded = false;
156 	m_bezier = NULL;
157 	m_displayBendpointCursor = m_canHaveCurve = true;
158 	m_hoverStrokeWidth = DefaultHoverStrokeWidth;
159 	m_connector0 = m_connector1 = NULL;
160 	m_partLabel = initLabel ? new PartLabel(this, NULL) : NULL;
161 	m_canChainMultiple = false;
162     setFlag(QGraphicsItem::ItemIsSelectable, true );
163 	m_connectorHover = NULL;
164 	m_opacity = 1.0;
165 	m_ignoreSelectionChange = false;
166 
167 	//DebugDialog::debug(QString("aix line %1 %2 %3 %4").arg(this->viewGeometry().line().x1())
168 													//.arg(this->viewGeometry().line().y1())
169 													//.arg(this->viewGeometry().line().x2())
170 													//.arg(this->viewGeometry().line().y2()) );
171 	//DebugDialog::debug(QString("aix loc %1 %2").arg(this->viewGeometry().loc().x())
172 														//.arg(this->viewGeometry().loc().y()) );
173 
174 	setPos(m_viewGeometry.loc());
175 
176 	m_dragCurve = m_dragEnd = false;
177 }
178 
~Wire()179 Wire::~Wire() {
180 	if (m_bezier) {
181 		delete m_bezier;
182 	}
183 }
184 
setUp(ViewLayer::ViewLayerID viewLayerID,const LayerHash & viewLayers,InfoGraphicsView * infoGraphicsView)185 FSvgRenderer * Wire::setUp(ViewLayer::ViewLayerID viewLayerID, const LayerHash &  viewLayers, InfoGraphicsView * infoGraphicsView) {
186 	ItemBase::setViewLayerID(viewLayerID, viewLayers);
187 	FSvgRenderer * svgRenderer = setUpConnectors(m_modelPart, m_viewID);
188 	if (svgRenderer != NULL) {
189 		initEnds(m_viewGeometry, svgRenderer->viewBox(), infoGraphicsView);
190         //debugCompare(this);
191 	}
192 	setZValue(this->z());
193 
194 	return svgRenderer;
195 }
196 
saveGeometry()197 void Wire::saveGeometry() {
198 	m_viewGeometry.setSelected(this->isSelected());
199 	m_viewGeometry.setLine(this->line());
200 	m_viewGeometry.setLoc(this->pos());
201 	m_viewGeometry.setZ(this->zValue());
202 }
203 
204 
itemMoved()205 bool Wire::itemMoved() {
206 	if  (m_viewGeometry.loc() != this->pos()) return true;
207 
208 	if (this->line().dx() != m_viewGeometry.line().dx()) return false;
209 	if (this->line().dy() != m_viewGeometry.line().dy()) return false;
210 
211 	return (this->line() != m_viewGeometry.line());
212 }
213 
moveItem(ViewGeometry & viewGeometry)214 void Wire::moveItem(ViewGeometry & viewGeometry) {
215 	this->setPos(viewGeometry.loc());
216 	this->setLine(viewGeometry.line());
217 }
218 
initEnds(const ViewGeometry & vg,QRectF defaultRect,InfoGraphicsView * infoGraphicsView)219 void Wire::initEnds(const ViewGeometry & vg, QRectF defaultRect, InfoGraphicsView * infoGraphicsView) {
220 	bool gotOne = false;
221 	bool gotTwo = false;
222 	double penWidth = 1;
223 	foreach (ConnectorItem * item, cachedConnectorItems()) {
224 		// check the name or is order good enough?
225 
226 		if (gotOne) {
227 			gotTwo = true;
228 			m_connector1 = item;
229 			break;
230 		}
231 		else {
232 			penWidth = item->rect().width();
233 			m_connector0 = item;
234 			gotOne = true;
235 		}
236 	}
237 
238 	if (!gotTwo) {
239 		return;
240 	}
241 
242 	if ((vg.line().length() == 0) && (vg.line().x1() == -1)) {
243 		this->setLine(defaultRect.left(), defaultRect.top(), defaultRect.right(), defaultRect.bottom());
244 	}
245 	else {
246 		this->setLine(vg.line());
247 	}
248 
249 	setConnector0Rect();
250 	setConnector1Rect();
251 	m_viewGeometry.setLine(this->line());
252 
253    	QBrush brush(QColor(0, 0, 0));
254 	QPen pen(brush, penWidth, Qt::SolidLine, Qt::RoundCap);
255 	this->setPen(pen);
256 
257 	m_pen.setCapStyle(Qt::RoundCap);
258 	m_shadowPen.setCapStyle(Qt::RoundCap);
259 	if (infoGraphicsView != NULL) {
260 		infoGraphicsView->initWire(this, penWidth);
261 	}
262 
263 	prepareGeometryChange();
264 }
265 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)266 void Wire::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget ) {
267 	if (m_hidden) return;
268 
269 	ItemBase::paint(painter, option, widget);
270 }
271 
paintBody(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)272 void Wire::paintBody(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
273 {
274 	Q_UNUSED(option);
275 	Q_UNUSED(widget);
276 
277 	QPainterPath painterPath;
278 	if (m_bezier && !m_bezier->isEmpty()) {
279 		QLineF line = this->line();
280 		painterPath.moveTo(line.p1());
281 		painterPath.cubicTo(m_bezier->cp0(), m_bezier->cp1(), line.p2());
282 
283 		/*
284 		DebugDialog::debug(QString("c0x:%1,c0y:%2 c1x:%3,c1y:%4 p0x:%5,p0y:%6 p1x:%7,p1y:%8 px:%9,py:%10")
285 							.arg(m_controlPoints.at(0).x())
286 							.arg(m_controlPoints.at(0).y())
287 							.arg(m_controlPoints.at(1).x())
288 							.arg(m_controlPoints.at(1).y())
289 							.arg(m_line.p1().x())
290 							.arg(m_line.p1().y())
291 							.arg(m_line.p2().x())
292 							.arg(m_line.p2().y())
293 							.arg(pos().x())
294 							.arg(pos().y())
295 
296 							);
297 		*/
298 	}
299 
300 
301 	painter->setOpacity(m_inactive ? m_opacity  / 2 : m_opacity);
302 	if (hasShadow()) {
303 		painter->save();
304 		painter->setPen(m_shadowPen);
305 		if (painterPath.isEmpty()) {
306 			QLineF line = this->line();
307 			painter->drawLine(line);
308 		}
309 		else {
310 			painter->drawPath(painterPath);
311 		}
312 		painter->restore();
313 	}
314 
315 	// DebugDialog::debug(QString("pen width %1 %2").arg(m_pen.widthF()).arg(m_viewID));
316 
317     if (m_banded) {
318         QBrush brush = m_pen.brush();
319         m_pen.setStyle(Qt::SolidLine);
320         m_pen.setBrush(BandedBrush);
321         painter->setPen(m_pen);
322 	    if (painterPath.isEmpty()) {
323 		    painter->drawLine(getPaintLine());
324 	    }
325 	    else {
326 		    painter->drawPath(painterPath);
327 	    }
328         m_pen.setBrush(brush);
329         m_pen.setDashPattern(TheDash);
330         m_pen.setCapStyle(Qt::FlatCap);
331     }
332 
333     if (getRatsnest()) {
334         m_pen.setDashPattern(RatDash);
335     }
336 	painter->setPen(m_pen);
337 	if (painterPath.isEmpty()) {
338 		painter->drawLine(getPaintLine());
339 	}
340 	else {
341 		painter->drawPath(painterPath);
342 	}
343 
344     if (m_banded) {
345         m_pen.setStyle(Qt::SolidLine);
346         m_pen.setCapStyle(Qt::RoundCap);
347     }
348 }
349 
paintHover(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)350 void Wire::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
351 {
352 	Q_UNUSED(widget);
353 	Q_UNUSED(option);
354 	painter->save();
355 	if ((m_connectorHoverCount > 0 && !(m_dragEnd || m_dragCurve)) || m_connectorHoverCount2 > 0) {
356 		painter->setOpacity(.50);
357 		painter->fillPath(this->hoverShape(), QBrush(ConnectorHoverColor));
358 	}
359 	else {
360 		painter->setOpacity(HoverOpacity);
361 		painter->fillPath(this->hoverShape(), QBrush(HoverColor));
362 	}
363 	painter->restore();
364 }
365 
hoverShape() const366 QPainterPath Wire::hoverShape() const
367 {
368 	return shapeAux(m_hoverStrokeWidth);
369 }
370 
shape() const371 QPainterPath Wire::shape() const
372 {
373 	return shapeAux(m_pen.widthF());
374 }
375 
shapeAux(double width) const376 QPainterPath Wire::shapeAux(double width) const
377 {
378 	QPainterPath path;
379 	if (m_line == QLineF()) {
380 	    return path;
381 	}
382 
383 	path.moveTo(m_line.p1());
384 	if (m_bezier == NULL || m_bezier->isEmpty()) {
385 		path.lineTo(m_line.p2());
386 	}
387 	else {
388 		path.cubicTo(m_bezier->cp0(), m_bezier->cp1(), m_line.p2());
389 	}
390 	//DebugDialog::debug(QString("using hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
391 	return GraphicsUtils::shapeFromPath(path, m_pen, width, false);
392 }
393 
boundingRect() const394 QRectF Wire::boundingRect() const
395 {
396 	if (m_pen.widthF() == 0.0) {
397 	    const double x1 = m_line.p1().x();
398 	    const double x2 = m_line.p2().x();
399 	    const double y1 = m_line.p1().y();
400 	    const double y2 = m_line.p2().y();
401 	    double lx = qMin(x1, x2);
402 	    double rx = qMax(x1, x2);
403 	    double ty = qMin(y1, y2);
404 	    double by = qMax(y1, y2);
405 	    return QRectF(lx, ty, rx - lx, by - ty);
406 	}
407 	return hoverShape().controlPointRect();
408 }
409 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)410 void Wire::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
411 	//DebugDialog::debug("checking press event");
412 	emit wireSplitSignal(this, event->scenePos(), this->pos(), this->line());
413 }
414 
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)415 void Wire::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
416 {
417 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
418 	if (infoGraphicsView != NULL) {
419 		infoGraphicsView->setActiveWire(this);
420 	}
421 
422 	ItemBase::contextMenuEvent(event);
423 }
424 
mousePressEvent(QGraphicsSceneMouseEvent * event)425 void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
426 {
427 	ItemBase::mousePressEvent(event);
428 }
429 
initDragCurve(QPointF scenePos)430 void Wire::initDragCurve(QPointF scenePos) {
431 	if (m_bezier == NULL) {
432 		m_bezier = new Bezier();
433 	}
434 
435 	UndoBezier.copy(m_bezier);
436 
437 	m_dragCurve = true;
438 	m_dragEnd = false;
439 
440 	QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
441 	QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
442 	if (m_bezier->isEmpty()) {
443 		m_bezier->initToEnds(mapFromScene(p0), mapFromScene(p1));
444 	}
445 	else {
446 		m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
447 	}
448 
449 	m_bezier->initControlIndex(mapFromScene(scenePos), m_pen.widthF());
450 	TheBezierDisplay = new BezierDisplay;
451 	TheBezierDisplay->initDisplay(this, m_bezier);
452 }
453 
initNewBendpoint(QPointF scenePos,Bezier & left,Bezier & right)454 bool Wire::initNewBendpoint(QPointF scenePos, Bezier & left, Bezier & right) {
455 	if (m_bezier == NULL || m_bezier->isEmpty()) {
456 		UndoBezier.clear();
457 		return false;
458 	}
459 
460 	QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
461 	QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
462 	m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
463 	UndoBezier.copy(m_bezier);
464 
465 	double t = m_bezier->findSplit(mapFromScene(scenePos), m_pen.widthF());
466 	m_bezier->split(t, left, right);
467 	return true;
468 }
469 
initDragEnd(ConnectorItem * connectorItem,QPointF scenePos)470 void Wire::initDragEnd(ConnectorItem * connectorItem, QPointF scenePos) {
471 	Q_UNUSED(scenePos);
472 	saveGeometry();
473 	QLineF line = this->line();
474 	m_drag0 = (connectorItem == m_connector0);
475     //debugInfo("setting drag end to true");
476 	m_dragEnd = true;
477 	m_dragCurve = false;
478 	if (m_drag0) {
479 		m_wireDragOrigin = line.p2();
480  		//DebugDialog::debug(QString("drag near origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
481 	}
482 	else {
483 		m_wireDragOrigin = line.p1();
484  		//DebugDialog::debug(QString("drag far origin %1 %2").arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y()) );
485  		//DebugDialog::debug(QString("drag far other %1 %2").arg(line.p2().x()).arg(line.p2().y()) );
486 	}
487 
488 	if (connectorItem->chained()) {
489 		QList<Wire *> chained;
490 		QList<ConnectorItem *> ends;
491 		collectChained(chained, ends);
492 		// already saved the first one
493 		for (int i = 1; i < chained.count(); i++) {
494 			chained[i]->saveGeometry();
495 		}
496 	}
497 }
498 
499 
mouseReleaseConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)500 void Wire::mouseReleaseConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
501 	Q_UNUSED(event);
502 	Q_UNUSED(connectorItem);
503 	releaseDrag();
504 }
505 
mouseMoveConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)506 void Wire::mouseMoveConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
507 	mouseMoveEventAux(this->mapFromItem(connectorItem, event->pos()), event->modifiers());
508 }
509 
mouseMoveEvent(QGraphicsSceneMouseEvent * event)510 void Wire::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
511 	mouseMoveEventAux(event->pos(), event->modifiers());
512 }
513 
mouseMoveEventAux(QPointF eventPos,Qt::KeyboardModifiers modifiers)514 void Wire::mouseMoveEventAux(QPointF eventPos, Qt::KeyboardModifiers modifiers) {
515 	if (m_spaceBarWasPressed) {
516 		return;
517 	}
518 
519 	if (m_dragCurve) {
520 		prepareGeometryChange();
521 		dragCurve(eventPos, modifiers);
522 		update();
523 		if (TheBezierDisplay) TheBezierDisplay->updateDisplay(this, m_bezier);
524 		return;
525 	}
526 
527 	if (m_dragEnd == false) {
528 		return;
529 	}
530 
531     //debugInfo("dragging wire");
532 
533 	ConnectorItem * whichConnectorItem;
534 	ConnectorItem * otherConnectorItem;
535 	if (m_drag0) {
536 		whichConnectorItem = m_connector0;
537 		otherConnectorItem = m_connector1;
538 	}
539 	else {
540 		whichConnectorItem = m_connector1;
541 		otherConnectorItem = m_connector0;
542 	}
543 
544 	if ((modifiers & Qt::ShiftModifier) != 0) {
545 		QPointF initialPos = mapFromScene(otherConnectorItem->sceneAdjustedTerminalPoint(NULL));
546 		bool bendpoint = isBendpoint(whichConnectorItem);
547 		if (bendpoint) {
548 			bendpoint = false;
549 			foreach (ConnectorItem * ci, whichConnectorItem->connectedToItems()) {
550 				Wire * w = qobject_cast<Wire *>(ci->attachedTo());
551 				ConnectorItem * oci = w->otherConnector(ci);
552 				QPointF otherInitialPos = mapFromScene(oci->sceneAdjustedTerminalPoint(NULL));
553 				QPointF p1(initialPos.x(), otherInitialPos.y());
554 				double d = GraphicsUtils::distanceSqd(p1, eventPos);
555 				if (d <= 144) {
556 					bendpoint = true;
557 					eventPos = p1;
558 					break;
559 				}
560 				p1.setX(otherInitialPos.x());
561 				p1.setY(initialPos.y());
562 				d = GraphicsUtils::distanceSqd(p1, eventPos);
563 				if (d <= 144) {
564 					bendpoint = true;
565 					eventPos = p1;
566 					break;
567 				}
568 			}
569 		}
570 
571 		if (!bendpoint) {
572 			eventPos = GraphicsUtils::calcConstraint(initialPos, eventPos);
573 		}
574 
575 	}
576 
577 	if (m_drag0) {
578 		QPointF p = this->mapToScene(eventPos);
579 		QGraphicsSvgItem::setPos(p.x(), p.y());
580 		this->setLine(0, 0, m_wireDragOrigin.x() - p.x() + m_viewGeometry.loc().x(),
581 							m_wireDragOrigin.y() - p.y() + m_viewGeometry.loc().y() );
582 		//DebugDialog::debug(QString("drag0 wdo:(%1,%2) p:(%3,%4) vg:(%5,%6) l:(%7,%8)")
583 		//			.arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
584 		//			.arg(p.x()).arg(p.y())
585 		//			.arg(m_viewGeometry.loc().x()).arg(m_viewGeometry.loc().y())
586 		//			.arg(line().p2().x()).arg(line().p2().y())
587 		//	);
588 	}
589 	else {
590 		this->setLine(m_wireDragOrigin.x(), m_wireDragOrigin.y(), eventPos.x(), eventPos.y());
591 		//DebugDialog::debug(QString("drag1 wdo:(%1,%2) ep:(%3,%4) p:(%5,%6) l:(%7,%8)")
592 		//			.arg(m_wireDragOrigin.x()).arg(m_wireDragOrigin.y())
593 		//			.arg(eventPos.x()).arg(eventPos.y())
594 		//			.arg(pos().x()).arg(pos().y())
595 		//			.arg(line().p2().x()).arg(line().p2().y())
596 		//	);
597 	}
598 	setConnector1Rect();
599 
600 
601     QSet<ConnectorItem *> allTo;
602     allTo.insert(whichConnectorItem);
603 	foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
604 		Wire * chainedWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
605 		if (chainedWire == NULL) continue;
606 
607         allTo.insert(toConnectorItem);
608         foreach (ConnectorItem * subTo, toConnectorItem->connectedToItems()) {
609             allTo.insert(subTo);
610         }
611 	}
612     allTo.remove(whichConnectorItem);
613 
614     // TODO: this could all be determined once at mouse press time
615 
616 	if (allTo.count() == 0) {
617         // dragging one end of the wire
618 
619 		// don't allow wire to connect back to something the other end is already directly connected to
620         // an alternative would be to exclude all connectors in the net connected by the same kind of trace
621 		QList<Wire *> wires;
622 		QList<ConnectorItem *> ends;
623 		collectChained(wires, ends);
624 
625         InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
626         //DebugDialog::debug("------------------------");
627 
628         QList<ConnectorItem *> exclude;
629         foreach (ConnectorItem * end, ends) {
630             exclude << end;
631             foreach (ConnectorItem * ci, end->connectedToItems()) {
632                 // if there is a wire growing out of one of the excluded ends, exclude the attached end
633                 exclude << ci;
634             }
635             foreach (ConnectorItem * toConnectorItem, end->connectedToItems()) {
636                 if (toConnectorItem->attachedToItemType() != ModelPart::Wire) continue;
637 
638                 Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
639                 if (w->getRatsnest()) continue;
640                 if (!w->isTraceType(infoGraphicsView->getTraceFlag())) continue;
641 
642                 //w->debugInfo("what wire");
643 
644                 QList<ConnectorItem *> ends2;
645                 QList<Wire *> wires2;
646                 w->collectChained(wires2, ends2);
647                 exclude.append(ends2);
648                 foreach (ConnectorItem * e2, ends2) {
649                     foreach (ConnectorItem * ci, e2->connectedToItems()) {
650                         // if there is a wire growing out of one of the excluded ends, exclude that end of the wire
651                         exclude << ci;
652                     }
653                 }
654                 foreach (Wire * w2, wires2) {
655 			        exclude.append(w2->cachedConnectorItems());
656 		        }
657             }
658         }
659 
660 
661         // but allow to restore connections at this end (collect chained above got both ends of this wire)
662 		foreach (ConnectorItem * toConnectorItem, whichConnectorItem->connectedToItems()) {
663 			if (ends.contains(toConnectorItem)) exclude.removeAll(toConnectorItem);
664 		}
665 
666         //DebugDialog::debug("");
667         //DebugDialog::debug("__________________");
668         //foreach (ConnectorItem * end, exclude) end->debugInfo("exclude");
669 
670         ConnectorItem * originatingConnector = NULL;
671 		if (otherConnectorItem) {
672 			foreach (ConnectorItem * toConnectorItem, otherConnectorItem->connectedToItems()) {
673 			    if (ends.contains(toConnectorItem)) {
674                     originatingConnector = toConnectorItem;
675                     break;
676                 }
677 		    }
678 		}
679 
680 		whichConnectorItem->findConnectorUnder(false, true, exclude, true, originatingConnector);
681 	}
682     else {
683         // dragging a bendpoint
684         foreach (ConnectorItem * toConnectorItem, allTo) {
685             Wire * chained = qobject_cast<Wire *>(toConnectorItem->attachedTo());
686             if (chained) {
687                 chained->simpleConnectedMoved(whichConnectorItem, toConnectorItem);
688             }
689         }
690     }
691 }
692 
setConnector0Rect()693 void Wire::setConnector0Rect() {
694 	QRectF rect = m_connector0->rect();
695 	rect.moveTo(0 - (rect.width()  / 2.0),
696 				0 - (rect.height()  / 2.0) );
697 	m_connector0->setRect(rect);
698 
699     //debugCompare(this);
700 
701 //	QPointF p = m_connector0->mapToScene(m_connector0->rect().center());
702 //	m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y()));
703 //	p = m_connector1->mapToScene(m_connector1->rect().center());
704 //	m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y()));
705 
706 }
707 
708 
setConnector1Rect()709 void Wire::setConnector1Rect() {
710 	QRectF rect = m_connector1->rect();
711 	rect.moveTo(this->line().dx() - (rect.width()  / 2.0),
712 				this->line().dy() - (rect.height()  / 2.0) );
713 	m_connector1->setRect(rect);
714 
715     //debugCompare(this);
716 
717 //	QPointF p = m_connector0->mapToScene(m_connector0->rect().center());
718 //	m_connector0->debugInfo(QString("c0:%1 %2").arg(p.x()).arg(p.y()));
719 //	p = m_connector1->mapToScene(m_connector1->rect().center());
720 //	m_connector1->debugInfo(QString("c1:%1 %2").arg(p.x()).arg(p.y()));
721 }
722 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)723 void Wire::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
724 	if (m_spaceBarWasPressed) {
725 		return;
726 	}
727 
728     //debugInfo("wire release drag");
729 	if (releaseDrag()) return;
730 
731 	ItemBase::mouseReleaseEvent(event);
732 }
733 
releaseDrag()734 bool Wire::releaseDrag() {
735 	if (m_dragEnd == false && m_dragCurve == false) return false;
736 
737 	if (m_dragCurve) {
738 		delete TheBezierDisplay;
739 		TheBezierDisplay = NULL;
740 		m_dragCurve = false;
741 		ungrabMouse();
742 		if (UndoBezier != *m_bezier) {
743 			emit wireChangedCurveSignal(this, &UndoBezier, m_bezier, false);
744 		}
745 		return true;
746 	}
747 
748     //debugInfo("clearing drag end");
749 	m_dragEnd = false;
750 
751 	ConnectorItem * from = (m_drag0) ? m_connector0 : m_connector1;
752 	ConnectorItem * to = from->releaseDrag();
753 
754 	QLineF newLine = this->line();
755 	QLineF oldLine = m_viewGeometry.line();
756 	QPointF oldPos = m_viewGeometry.loc();
757 	QPointF newPos = this->pos();
758 	if (newLine != oldLine || oldPos != newPos) {
759 		emit wireChangedSignal(this, oldLine, newLine, oldPos, newPos, from, to);
760 	}
761 
762 	return true;
763 }
764 
765 
saveInstanceLocation(QXmlStreamWriter & streamWriter)766 void Wire::saveInstanceLocation(QXmlStreamWriter & streamWriter)
767 {
768 	QLineF line = m_viewGeometry.line();
769 	QPointF loc = m_viewGeometry.loc();
770 	streamWriter.writeAttribute("x", QString::number(loc.x()));
771 	streamWriter.writeAttribute("y", QString::number(loc.y()));
772 	streamWriter.writeAttribute("x1", QString::number(line.x1()));
773 	streamWriter.writeAttribute("y1", QString::number(line.y1()));
774 	streamWriter.writeAttribute("x2", QString::number(line.x2()));
775 	streamWriter.writeAttribute("y2", QString::number(line.y2()));
776 	streamWriter.writeAttribute("wireFlags", QString::number(m_viewGeometry.flagsAsInt()));
777 }
778 
writeGeometry(QXmlStreamWriter & streamWriter)779 void Wire::writeGeometry(QXmlStreamWriter & streamWriter) {
780 	ItemBase::writeGeometry(streamWriter);
781 	streamWriter.writeStartElement("wireExtras");
782 	streamWriter.writeAttribute("mils", QString::number(mils()));
783 	streamWriter.writeAttribute("color", m_pen.brush().color().name());
784 	streamWriter.writeAttribute("opacity", QString::number(m_opacity));
785 	streamWriter.writeAttribute("banded", m_banded ? "1" : "0");
786 	if (m_bezier) m_bezier->write(streamWriter);
787 	streamWriter.writeEndElement();
788 }
789 
setExtras(QDomElement & element,InfoGraphicsView * infoGraphicsView)790 void Wire::setExtras(QDomElement & element, InfoGraphicsView * infoGraphicsView)
791 {
792 	if (element.isNull()) return;
793 
794 	bool ok;
795 	double w = element.attribute("width").toDouble(&ok);
796 	if (ok) {
797 		setWireWidth(w, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, w));
798 	}
799 	else {
800 		w = element.attribute("mils").toDouble(&ok);
801 		if (ok) {
802 			double wpix = GraphicsUtils::mils2pixels(w, GraphicsUtils::SVGDPI);
803 			setWireWidth(wpix, infoGraphicsView, infoGraphicsView->getWireStrokeWidth(this, wpix));
804 		}
805 	}
806 
807     m_banded = (element.attribute("banded", "") == "1");
808 
809 	setColorFromElement(element);
810 	QDomElement bElement = element.firstChildElement("bezier");
811 	Bezier bezier = Bezier::fromElement(bElement);
812 	if (!bezier.isEmpty()) {
813 		prepareGeometryChange();
814 		m_bezier = new Bezier;
815 		m_bezier->copy(&bezier);
816 		QPointF p0 = connector0()->sceneAdjustedTerminalPoint(NULL);
817 		QPointF p1 = connector1()->sceneAdjustedTerminalPoint(NULL);
818 		m_bezier->set_endpoints(mapFromScene(p0), mapFromScene(p1));
819 	}
820 
821 }
822 
setColorFromElement(QDomElement & element)823 void Wire::setColorFromElement(QDomElement & element) {
824 	QString colorString = element.attribute("color");
825 	if (colorString.isNull() || colorString.isEmpty()) return;
826 
827 	bool ok;
828 	double op = element.attribute("opacity").toDouble(&ok);
829 	if (!ok) {
830 		op = 1.0;
831 	}
832 
833 	setColorString(colorString, op, false);
834 }
835 
hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event,ConnectorItem * item)836 void Wire::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * event , ConnectorItem * item) {
837 	m_connectorHover = item;
838 	ItemBase::hoverEnterConnectorItem(event, item);
839 }
840 
hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event,ConnectorItem * item)841 void Wire::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * event, ConnectorItem * item) {
842 	m_connectorHover = NULL;
843 	ItemBase::hoverLeaveConnectorItem(event, item);
844 }
845 
hoverEnterEvent(QGraphicsSceneHoverEvent * event)846 void Wire::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) {
847 	ItemBase::hoverEnterEvent(event);
848 	CursorMaster::instance()->addCursor(this, cursor());
849 	//DebugDialog::debug("---wire set override cursor");
850 	updateCursor(event->modifiers());
851 }
852 
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)853 void Wire::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) {
854 	ItemBase::hoverLeaveEvent(event);
855 	//DebugDialog::debug("------wire restore override cursor");
856 	CursorMaster::instance()->removeCursor(this);
857 }
858 
859 
connectionChange(ConnectorItem * onMe,ConnectorItem * onIt,bool connect)860 void Wire::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
861 	checkVisibility(onMe, onIt, connect);
862 
863 	bool movable = true;
864 	foreach (ConnectorItem * connectedTo, m_connector0->connectedToItems()) {
865 		if (connectedTo->attachedToItemType() != ModelPart::Wire) {
866 			movable = false;
867 			break;
868 		}
869 	}
870 	if (movable) {
871 		foreach (ConnectorItem * connectedTo, m_connector1->connectedToItems()) {
872 			if (connectedTo->attachedToItemType() != ModelPart::Wire) {
873 				movable = false;
874 				break;
875 			}
876 		}
877 	}
878 }
879 
mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem)880 void Wire::mouseDoubleClickConnectorEvent(ConnectorItem * connectorItem) {
881 	int chained = 0;
882 	foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
883 		if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
884 			chained++;
885 		}
886 		else {
887 			return;
888 		}
889 	}
890 
891 
892 	if (chained == 1) {
893 		// near as I can tell, this is to eliminate the overrides from the connectorItem and then from the wire itself
894 		emit wireJoinSignal(this, connectorItem);
895 	}
896 }
897 
mousePressConnectorEvent(ConnectorItem * connectorItem,QGraphicsSceneMouseEvent * event)898 void Wire::mousePressConnectorEvent(ConnectorItem * connectorItem, QGraphicsSceneMouseEvent * event) {
899 	//DebugDialog::debug("checking press connector event");
900 
901 	if (m_canChainMultiple && event->modifiers() & altOrMetaModifier()) {
902 		// dragging a wire out of a bendpoint
903 		InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
904 		if (infoGraphicsView != NULL) {
905 			infoGraphicsView->mousePressConnectorEvent(connectorItem, event);
906 		}
907 
908 		return;
909 	}
910 
911 
912 	connectorItem->setOverConnectorItem(NULL);
913 	initDragEnd(connectorItem, event->scenePos());
914 
915 }
916 
simpleConnectedMoved(ConnectorItem * to)917 void Wire::simpleConnectedMoved(ConnectorItem * to) {
918 	// to is this wire, from is something else
919 	simpleConnectedMoved(to->firstConnectedToIsh(), to);
920 }
921 
simpleConnectedMoved(ConnectorItem * from,ConnectorItem * to)922 void Wire::simpleConnectedMoved(ConnectorItem * from, ConnectorItem * to)
923 {
924 	if (from == NULL) return;
925 
926     //if (from) from->debugInfo("connected moved from");
927     //if (to) to->debugInfo("\tto");
928 
929 	// to is this wire, from is something else
930 	QPointF p1, p2;
931 	calcNewLine(from, to, p1, p2);
932 
933 	/*
934 	QPointF oldPos = this->pos();
935 	QPointF newPos = p1;
936 	QLineF oldLine = this->line();
937 	QLineF newLine(0, 0,  p2.x() - p1.x(), p2.y() - p1.y());
938 	if (qAbs(oldPos.x() - newPos.x()) > 1.75 ||
939 		qAbs(oldPos.y() - newPos.y()) > 1.75 ||
940 		qAbs(oldLine.x1() - newLine.x1()) > 1.75 ||
941 		qAbs(oldLine.x2() - newLine.x2()) > 1.75 ||
942 		qAbs(oldLine.y1() - newLine.y1()) > 1.75 ||
943 		qAbs(oldLine.y2() - newLine.y2()) > 1.75
944 		)
945 	{
946 		DebugDialog::debug("line changed");
947 		calcNewLine(from,to,p1,p2);
948 	}
949 	*/
950 
951 	this->setPos(p1);
952 	this->setLine(0,0, p2.x() - p1.x(), p2.y() - p1.y() );
953 	//debugInfo(QString("set line  %1 %2, %3 %4, vis:%5").arg(p1.x()).arg(p1.y()).arg(p2.x()).arg(p2.y()).arg(isVisible()) );
954 	setConnector1Rect();
955 }
956 
calcNewLine(ConnectorItem * from,ConnectorItem * to,QPointF & p1,QPointF & p2)957 void Wire::calcNewLine(ConnectorItem * from, ConnectorItem * to, QPointF & p1, QPointF & p2) {
958 	// to is this wire, from is something else
959 	if (to == m_connector0) {
960 		p1 = from->sceneAdjustedTerminalPoint(to);
961 		ConnectorItem * otherFrom = m_connector1->firstConnectedToIsh();
962 		if (otherFrom == NULL) {
963 			p2 = m_connector1->mapToScene(m_connector1->rect().center());
964 		}
965 		else {
966 			p2 = otherFrom->sceneAdjustedTerminalPoint(m_connector1);
967 		}
968 	}
969 	else {
970 		p2 = from->sceneAdjustedTerminalPoint(to);
971 		ConnectorItem * otherFrom = m_connector0->firstConnectedToIsh();
972 		if (otherFrom == NULL) {
973 			p1 = m_connector0->mapToScene(m_connector0->rect().center());
974 		}
975 		else {
976 			p1 = otherFrom->sceneAdjustedTerminalPoint(m_connector0);
977 		}
978 
979 	}
980 }
981 
connectedMoved(ConnectorItem * from,ConnectorItem * to,QList<ConnectorItem * > & already)982 void Wire::connectedMoved(ConnectorItem * from, ConnectorItem * to, QList<ConnectorItem *> & already) {
983     Q_UNUSED(already);
984 
985 	// "from" is the connector on the part
986 	// "to" is the connector on the wire
987 
988     //from->debugInfo("connected moved");
989     //to->debugInfo("\tconnected moved");
990 
991     if (from->connectedToItems().contains(to) || to->connectedToItems().contains(from)) {
992 	    simpleConnectedMoved(from, to);
993     }
994     else {
995         //from->debugInfo("not connected");
996         //to->debugInfo("\t");
997     }
998 }
999 
1000 
setUpConnectors(ModelPart * modelPart,ViewLayer::ViewID viewID)1001 FSvgRenderer * Wire::setUpConnectors(ModelPart * modelPart, ViewLayer::ViewID viewID)
1002 {
1003 	clearConnectorItemCache();
1004 
1005 	LayerAttributes layerAttributes;
1006     this->initLayerAttributes(layerAttributes, viewID, m_viewLayerID, m_viewLayerPlacement, false, false);
1007 	FSvgRenderer * renderer = ItemBase::setUpImage(modelPart, layerAttributes);
1008 	if (renderer == NULL) {
1009 		return NULL;
1010 	}
1011 
1012 	foreach (Connector * connector, modelPart->connectors().values()) {
1013 		if (connector == NULL) continue;
1014 
1015 		SvgIdLayer * svgIdLayer = connector->fullPinInfo(viewID, m_viewLayerID);
1016 		if (svgIdLayer == NULL) continue;
1017 
1018 		bool result = renderer->setUpConnector(svgIdLayer, false, viewLayerPlacement());
1019 		if (!result) continue;
1020 
1021 		ConnectorItem * connectorItem = newConnectorItem(connector);
1022 		connectorItem->setRect(svgIdLayer->rect(viewLayerPlacement()));
1023 		connectorItem->setTerminalPoint(svgIdLayer->point(viewLayerPlacement()));
1024 		m_originalConnectorRect = svgIdLayer->rect(viewLayerPlacement());
1025 
1026 		connectorItem->setCircular(true);
1027 		//DebugDialog::debug(QString("terminal point %1 %2").arg(terminalPoint.x()).arg(terminalPoint.y()) );
1028 	}
1029 
1030 	return renderer;
1031 }
1032 
1033 /*
1034 void Wire::setPos(const QPointF & pos) {
1035 	ItemBase::setPos(pos);
1036 }
1037 */
1038 
1039 
setLineAnd(QLineF line,QPointF pos,bool useLine)1040 void Wire::setLineAnd(QLineF line, QPointF pos, bool useLine) {
1041 	this->setPos(pos);
1042 	if (useLine) this->setLine(line);
1043 
1044 	setConnector1Rect();
1045 }
1046 
otherConnector(ConnectorItem * oneConnector)1047 ConnectorItem * Wire::otherConnector(ConnectorItem * oneConnector) {
1048 	if (oneConnector == m_connector0) return m_connector1;
1049 
1050 	return m_connector0;
1051 }
1052 
connector0()1053 ConnectorItem * Wire::connector0() {
1054 	return m_connector0;
1055 }
1056 
connector1()1057 ConnectorItem * Wire::connector1() {
1058 	return m_connector1;
1059 }
1060 
findConnectorsUnder()1061 void Wire::findConnectorsUnder() {
1062 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1063 		if (connectorItem->connectionsCount() > 0) continue;  // only check free ends
1064 		connectorItem->findConnectorUnder(true, false, ConnectorItem::emptyConnectorItemList, false, NULL);
1065 	}
1066 }
1067 
collectChained(QList<Wire * > & chained,QList<ConnectorItem * > & ends)1068 void Wire::collectChained(QList<Wire *> & chained, QList<ConnectorItem *> & ends ) {
1069 	chained.append(this);
1070 	for (int i = 0; i < chained.count(); i++) {
1071 		Wire * wire = chained[i];
1072 		collectChained(wire->m_connector1, chained, ends);
1073 		collectChained(wire->m_connector0, chained, ends);
1074 	}
1075 }
1076 
collectChained(ConnectorItem * connectorItem,QList<Wire * > & chained,QList<ConnectorItem * > & ends)1077 void Wire::collectChained(ConnectorItem * connectorItem, QList<Wire *> & chained, QList<ConnectorItem *> & ends) {
1078 	if (connectorItem == NULL) return;
1079 
1080 	foreach (ConnectorItem * connectedToItem, connectorItem->connectedToItems()) {
1081 		Wire * wire = qobject_cast<Wire *>(connectedToItem->attachedTo());
1082 		if (wire == NULL) {
1083 			if (!ends.contains(connectedToItem)) {
1084 				ends.append(connectedToItem);
1085 			}
1086 			continue;
1087 		}
1088 
1089 		if (chained.contains(wire)) continue;
1090 		chained.append(wire);
1091 	}
1092 }
1093 
collectWires(QList<Wire * > & wires)1094 void Wire::collectWires(QList<Wire *> & wires) {
1095 	if (wires.contains(this)) return;
1096 
1097 	wires.append(this);
1098 	//DebugDialog::debug(QString("collecting wire %1").arg(this->id()) );
1099 	collectWiresAux(wires, m_connector0);
1100 	collectWiresAux(wires, m_connector1);
1101 }
1102 
collectWiresAux(QList<Wire * > & wires,ConnectorItem * start)1103 void Wire::collectWiresAux(QList<Wire *> & wires, ConnectorItem * start) {
1104 	foreach (ConnectorItem * toConnectorItem, start->connectedToItems()) {
1105 		if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
1106 			qobject_cast<Wire *>(toConnectorItem->attachedTo())->collectWires(wires);
1107 		}
1108 	}
1109 
1110 }
1111 
stickyEnabled()1112 bool Wire::stickyEnabled()
1113 {
1114 	QList<Wire *> wires;
1115 	QList<ConnectorItem *> ends;
1116 	this->collectChained(wires, ends);
1117 	foreach (ConnectorItem * connector, ends) {
1118 		if (connector->connectionsCount() > 0) {
1119 			return false;
1120 		}
1121 	}
1122 
1123 	return true;
1124 }
1125 
getTrace()1126 bool Wire::getTrace() {
1127 	return m_viewGeometry.getAnyTrace();
1128 }
1129 
getRouted()1130 bool Wire::getRouted() {
1131 	return m_viewGeometry.getRouted();
1132 }
1133 
setRouted(bool routed)1134 void Wire::setRouted(bool routed) {
1135 	m_viewGeometry.setRouted(routed);
1136 }
1137 
setRatsnest(bool ratsnest)1138 void Wire::setRatsnest(bool ratsnest) {
1139 	m_viewGeometry.setRatsnest(ratsnest);
1140 }
1141 
setAutoroutable(bool ar)1142 void Wire::setAutoroutable(bool ar) {
1143 	m_viewGeometry.setAutoroutable(ar);
1144 }
1145 
getAutoroutable()1146 bool Wire::getAutoroutable() {
1147 	return m_viewGeometry.getAutoroutable();
1148 }
1149 
setNormal(bool normal)1150 void Wire::setNormal(bool normal) {
1151 	m_viewGeometry.setNormal(normal);
1152 }
1153 
getNormal()1154 bool Wire::getNormal() {
1155 	return m_viewGeometry.getNormal();
1156 }
1157 
setColor(const QColor & color,double op)1158 void Wire::setColor(const QColor & color, double op) {
1159 	m_pen.setBrush(QBrush(color));
1160 	m_opacity = op;
1161 	m_colorName = color.name();
1162 	this->update();
1163 }
1164 
setShadowColor(QColor & color,bool restore)1165 void Wire::setShadowColor(QColor & color, bool restore) {
1166 	m_shadowBrush = QBrush(color);
1167 	m_shadowPen.setBrush(m_shadowBrush);
1168 	m_bendpointPen.setBrush(m_shadowBrush);
1169 	m_bendpoint2Pen.setBrush(m_shadowBrush);
1170     QList<ConnectorItem *> visited;
1171     if (restore) {
1172 	    if (m_connector0) m_connector0->restoreColor(visited);
1173 	    if (m_connector1) m_connector1->restoreColor(visited);
1174     }
1175 	this->update();
1176 }
1177 
color()1178 const QColor & Wire::color() {
1179 	return m_pen.brush().color();
1180 }
1181 
setWireWidth(double width,InfoGraphicsView * infoGraphicsView,double hoverStrokeWidth)1182 void Wire::setWireWidth(double width, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1183 	if (m_pen.widthF() == width) return;
1184 
1185 	prepareGeometryChange();
1186 	setPenWidth(width, infoGraphicsView, hoverStrokeWidth);
1187     QList<ConnectorItem *> visited;
1188 	if (m_connector0) m_connector0->restoreColor(visited);
1189 	if (m_connector1) m_connector1->restoreColor(visited);
1190 	update();
1191 }
1192 
width()1193 double Wire::width() {
1194 	return m_pen.widthF();
1195 }
1196 
shadowWidth()1197 double Wire::shadowWidth() {
1198 	return m_shadowPen.widthF();
1199 }
1200 
mils()1201 double Wire::mils() {
1202 	return 1000 * m_pen.widthF() / GraphicsUtils::SVGDPI;
1203 }
1204 
setColorString(QString colorName,double op,bool restore)1205 void Wire::setColorString(QString colorName, double op, bool restore) {
1206 	// sets a color using the name (.e. "red")
1207 	// note: colorName is associated with a Fritzing color, not a Qt color
1208 
1209 	QString colorString = RatsnestColors::wireColor(m_viewID, colorName);
1210 	if (colorString.isEmpty()) {
1211 		colorString = colorName;
1212 	}
1213 
1214 	QColor c;
1215 	c.setNamedColor(colorString);
1216 	setColor(c, op);
1217 	m_colorName = colorName;
1218 
1219 	QString shadowColorString = RatsnestColors::shadowColor(m_viewID, colorName);
1220 	if (shadowColorString.isEmpty()) {
1221 		shadowColorString = colorString;
1222 	}
1223 
1224 	c.setNamedColor(shadowColorString);
1225 	setShadowColor(c, restore);
1226 }
1227 
hexString()1228 QString Wire::hexString() {
1229 	return m_pen.brush().color().name();
1230 }
1231 
shadowHexString()1232 QString Wire::shadowHexString() {
1233 	return m_shadowPen.brush().color().name();
1234 }
1235 
colorString()1236 QString Wire::colorString() {
1237 	return m_colorName;
1238 }
1239 
initNames()1240 void Wire::initNames() {
1241 	if (colorNames.count() > 0) return;
1242 
1243     TheDash.clear();
1244     TheDash << 10 << 8;
1245     RatDash.clear();
1246     RatDash << 2 << 2;
1247 
1248 	widths << 8 << 12 << 16 << 24 << 32 << 48;
1249     int i = 0;
1250 	widthTrans.insert(widths[i++], tr("super fine (8 mil)"));
1251 	widthTrans.insert(widths[i++], tr("extra thin (12 mil)"));
1252 
1253 	THIN_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI);
1254 	widthTrans.insert(widths[i++], tr("thin (16 mil)"));
1255 
1256 	STANDARD_TRACE_WIDTH = GraphicsUtils::mils2pixels(widths[i], GraphicsUtils::SVGDPI);
1257 	widthTrans.insert(widths[i++], tr("standard (24 mil)"));
1258 
1259 	widthTrans.insert(widths[i++], tr("thick (32 mil)"));
1260 	widthTrans.insert(widths[i++], tr("extra thick (48 mil)"));
1261 
1262 	HALF_STANDARD_TRACE_WIDTH = STANDARD_TRACE_WIDTH / 2.0;
1263 
1264     // need a list because a hash table doesn't guarantee order
1265     colorNames.append(tr("blue"));
1266 	colorNames.append(tr("red"));
1267     colorNames.append(tr("black"));
1268 	colorNames.append(tr("yellow"));
1269 	colorNames.append(tr("green"));
1270 	colorNames.append(tr("grey"));
1271 	colorNames.append(tr("white"));
1272     colorNames.append(tr("orange"));
1273     colorNames.append(tr("ochre"));
1274     colorNames.append(tr("cyan"));
1275     colorNames.append(tr("brown"));
1276     colorNames.append(tr("purple"));
1277     colorNames.append(tr("pink"));
1278 
1279 	// need this hash table to translate from user's language to internal color name
1280     colorTrans.insert(tr("blue"), "blue");
1281 	colorTrans.insert(tr("red"), "red");
1282     colorTrans.insert(tr("black"), "black");
1283 	colorTrans.insert(tr("yellow"), "yellow");
1284 	colorTrans.insert(tr("green"), "green");
1285 	colorTrans.insert(tr("grey"), "grey");
1286 	colorTrans.insert(tr("white"), "white");
1287     colorTrans.insert(tr("orange"), "orange");
1288     colorTrans.insert(tr("ochre"), "ochre");
1289     colorTrans.insert(tr("cyan"), "cyan");
1290 	colorTrans.insert(tr("brown"), "brown");
1291     colorTrans.insert(tr("purple"), "purple");
1292     colorTrans.insert(tr("pink"), "pink");
1293 }
1294 
hasFlag(ViewGeometry::WireFlag flag)1295 bool Wire::hasFlag(ViewGeometry::WireFlag flag)
1296 {
1297 	return m_viewGeometry.hasFlag(flag);
1298 }
1299 
isTraceType(ViewGeometry::WireFlag flag)1300 bool Wire::isTraceType(ViewGeometry::WireFlag flag) {
1301 	return hasFlag(flag);
1302 }
1303 
hasAnyFlag(ViewGeometry::WireFlags flags)1304 bool Wire::hasAnyFlag(ViewGeometry::WireFlags flags)
1305 {
1306 	return m_viewGeometry.hasAnyFlag(flags);
1307 }
1308 
findTraced(ViewGeometry::WireFlags flags,QList<ConnectorItem * > & ends)1309 Wire * Wire::findTraced(ViewGeometry::WireFlags flags, QList<ConnectorItem *>  & ends) {
1310 	QList<Wire *> chainedWires;
1311 	this->collectChained(chainedWires, ends);
1312 	if (ends.count() != 2) {
1313 		DebugDialog::debug(QString("wire in jumper or trace must have two ends") );
1314 		return NULL;
1315 	}
1316 
1317 	return ConnectorItem::directlyWiredTo(ends[0], ends[1], flags);
1318 }
1319 
setWireFlags(ViewGeometry::WireFlags wireFlags)1320 void Wire::setWireFlags(ViewGeometry::WireFlags wireFlags) {
1321 	m_viewGeometry.setWireFlags(wireFlags);
1322 }
1323 
opacity()1324 double Wire::opacity() {
1325 	return m_opacity;
1326 }
1327 
setOpacity(double opacity)1328 void Wire::setOpacity(double opacity) {
1329 	m_opacity = opacity;
1330 	this->update();
1331 }
1332 
draggingEnd()1333 bool Wire::draggingEnd() {
1334 	return m_dragEnd || m_dragCurve;
1335 }
1336 
setCanChainMultiple(bool can)1337 void Wire::setCanChainMultiple(bool can) {
1338 	m_canChainMultiple = can;
1339 }
1340 
canChangeColor()1341 bool Wire::canChangeColor() {
1342 	if (getRatsnest()) return false;
1343 	if (!getTrace()) return true;
1344 
1345 	return (this->m_viewID == ViewLayer::SchematicView);
1346 }
1347 
collectDirectWires(QList<Wire * > & wires)1348 void Wire::collectDirectWires(QList<Wire *> & wires) {
1349     bool firstRound = false;
1350 	if (!wires.contains(this)) {
1351 		wires.append(this);
1352         firstRound = true;
1353 	}
1354 
1355     QList<ConnectorItem *> junctions;
1356     if (firstRound) {
1357         // collect up to any junction
1358 	    collectDirectWires(m_connector0, wires, junctions);
1359 	    collectDirectWires(m_connector1, wires, junctions);
1360         return;
1361     }
1362 
1363     // second round: deal with junctions
1364     foreach (Wire * wire, wires) {
1365         junctions << wire->connector0() << wire->connector1();
1366     }
1367 
1368     int ix = 0;
1369     while (ix < junctions.count()) {
1370         ConnectorItem * junction = junctions.at(ix++);
1371 
1372         QSet<Wire *> jwires;
1373         foreach (ConnectorItem * toConnectorItem, junction->connectedToItems()) {
1374             if (toConnectorItem->attachedToItemType() != ModelPart::Wire) break;
1375 
1376             Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1377             if (!wires.contains(w)) jwires << w;
1378 
1379             bool onlyWiresConnected = true;
1380             foreach (ConnectorItem * toToConnectorItem, toConnectorItem->connectedToItems()) {
1381                 if (toToConnectorItem->attachedToItemType() != ModelPart::Wire) {
1382                     onlyWiresConnected = false;
1383                     break;
1384                 }
1385 
1386                 w = qobject_cast<Wire *>(toToConnectorItem->attachedTo());
1387                 if (!wires.contains(w)) jwires << w;
1388             }
1389             if (!onlyWiresConnected) break;
1390         }
1391 
1392         if (jwires.count() == 1) {
1393             // there is a junction of > 2 wires and all wires leading to it except one are already on the delete list
1394             Wire * w = jwires.values().at(0);
1395             wires << w;
1396             w->collectDirectWires(w->connector0(), wires, junctions);
1397             w->collectDirectWires(w->connector1(), wires, junctions);
1398         }
1399     }
1400 }
1401 
1402 
collectDirectWires(ConnectorItem * connectorItem,QList<Wire * > & wires,QList<ConnectorItem * > & junctions)1403 void Wire::collectDirectWires(ConnectorItem * connectorItem, QList<Wire *> & wires, QList<ConnectorItem *> & junctions) {
1404 	if (connectorItem->connectionsCount() == 0) return;
1405     if (connectorItem->connectionsCount() > 1) {
1406         if (!junctions.contains(connectorItem)) junctions.append(connectorItem);
1407         return;
1408     }
1409 
1410 	ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0);
1411 	if (toConnectorItem->attachedToItemType() != ModelPart::Wire) return;
1412 
1413     if (toConnectorItem->connectionsCount() != 1) {
1414         if (!junctions.contains(connectorItem)) junctions.append(connectorItem);
1415         return;
1416     }
1417 
1418 	Wire * nextWire = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1419 	if (wires.contains(nextWire)) return;
1420 
1421 	wires.append(nextWire);
1422 	nextWire->collectDirectWires(nextWire->otherConnector(toConnectorItem), wires, junctions);
1423 }
1424 
itemChange(GraphicsItemChange change,const QVariant & value)1425 QVariant Wire::itemChange(GraphicsItemChange change, const QVariant &value)
1426 {
1427     if (change == ItemSelectedChange) {
1428 		if (m_partLabel) {
1429 			m_partLabel->update();
1430 		}
1431 
1432 		if (!m_ignoreSelectionChange) {
1433 			QList<Wire *> chained;
1434 			QList<ConnectorItem *> ends;
1435 			collectChained(chained, ends);
1436 			InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1437 			if (infoGraphicsView) {
1438 				infoGraphicsView->setIgnoreSelectionChangeEvents(true);
1439 			}
1440 			// DebugDialog::debug(QString("original wire selected %1 %2").arg(value.toBool()).arg(this->id()));
1441 			foreach (Wire * wire, chained) {
1442 				if (wire != this ) {
1443 					wire->setIgnoreSelectionChange(true);
1444 					wire->setSelected(value.toBool());
1445 					wire->setIgnoreSelectionChange(false);
1446 					// DebugDialog::debug(QString("wire selected %1 %2").arg(value.toBool()).arg(wire->id()));
1447 				}
1448 			}
1449 			if (infoGraphicsView) {
1450 				infoGraphicsView->setIgnoreSelectionChangeEvents(false);
1451 			}
1452 		}
1453     }
1454     return ItemBase::itemChange(change, value);
1455 }
1456 
cleanup()1457 void Wire::cleanup() {
1458 }
1459 
getConnectedColor(ConnectorItem * connectorItem,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1460 void Wire::getConnectedColor(ConnectorItem * connectorItem, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect)
1461 {
1462 	connectorItem->setBigDot(false);
1463 	ItemBase::getConnectedColor(connectorItem, brush, pen, opacity, negativePenWidth, negativeOffsetRect);
1464 	int count = 0;
1465 	bool bendpoint = true;
1466 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1467 	if (infoGraphicsView == NULL) {
1468 		return;
1469     }
1470 
1471 	foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
1472 		if (toConnectorItem->attachedToItemType() == ModelPart::Wire) {
1473 			Wire * w = qobject_cast<Wire *>(toConnectorItem->attachedTo());
1474 			if (w->isTraceType(infoGraphicsView->getTraceFlag())) {
1475 				count++;
1476 			}
1477 		}
1478 		else {
1479 			// for drawing a big dot on the end of a part connector in schematic view if the part is connected to more than one trace
1480 			bendpoint = false;
1481 			if (toConnectorItem->connectionsCount() > 1) {
1482 				if (infoGraphicsView->hasBigDots()) {
1483 					int c = 0;
1484 					foreach (ConnectorItem * totoConnectorItem, toConnectorItem->connectedToItems()) {
1485 						if (totoConnectorItem->attachedToItemType() == ModelPart::Wire) {
1486 							Wire * w = qobject_cast<Wire *>(totoConnectorItem->attachedTo());
1487 							if (w && w->isTraceType(ViewGeometry::SchematicTraceFlag) && w->isTraceType(infoGraphicsView->getTraceFlag())) {
1488 								c++;
1489 							}
1490 						}
1491 					}
1492 					if (c > 1) {
1493 						count = 2;
1494 						break;
1495 					}
1496 				}
1497 			}
1498 
1499 			count = 0;
1500 			break;
1501 		}
1502 	}
1503 
1504 	if (count == 0) {
1505 		return;
1506 	}
1507 
1508 	// connectorItem is a bendpoint or connects to a multiply connected connector
1509 
1510 	//if (!bendpoint) {
1511 		//DebugDialog::debug(QString("big dot %1 %2 %3").arg(this->id()).arg(connectorItem->connectorSharedID()).arg(count));
1512 	//}
1513 
1514 	brush = m_shadowBrush;
1515 	opacity = 1.0;
1516 	if (count > 1) {
1517 		// only ever reach here when drawing a connector that is connected to more than one trace
1518 		pen = m_bendpoint2Pen;
1519 		negativePenWidth = m_bendpoint2Width;
1520 		negativeOffsetRect = m_negativeOffsetRect;
1521 		connectorItem->setBigDot(true);
1522 	}
1523 	else {
1524 		negativeOffsetRect = m_negativeOffsetRect;
1525 		negativePenWidth = m_bendpointWidth;
1526 		pen = m_bendpointPen;
1527 	}
1528 }
1529 
setPenWidth(double w,InfoGraphicsView * infoGraphicsView,double hoverStrokeWidth)1530 void Wire::setPenWidth(double w, InfoGraphicsView * infoGraphicsView, double hoverStrokeWidth) {
1531 	m_hoverStrokeWidth = hoverStrokeWidth;
1532 	//DebugDialog::debug(QString("setting hoverstrokewidth %1 %2").arg(m_id).arg(m_hoverStrokeWidth));
1533 	m_pen.setWidthF(w);
1534 	infoGraphicsView->getBendpointWidths(this, w, m_bendpointWidth, m_bendpoint2Width, m_negativeOffsetRect);
1535 	m_bendpointPen.setWidthF(qAbs(m_bendpointWidth));
1536 	m_bendpoint2Pen.setWidthF(qAbs(m_bendpoint2Width));
1537 	m_shadowPen.setWidthF(w + 2);
1538 }
1539 
connectionIsAllowed(ConnectorItem * to)1540 bool Wire::connectionIsAllowed(ConnectorItem * to) {
1541 	if (!ItemBase::connectionIsAllowed(to)) return false;
1542 
1543 	Wire * w = qobject_cast<Wire *>(to->attachedTo());
1544 	if (w == NULL) return true;
1545 
1546 	if (w->getRatsnest()) return false;
1547 
1548 	return m_viewID != ViewLayer::BreadboardView;
1549 }
1550 
isGrounded()1551 bool Wire::isGrounded() {
1552 	return ConnectorItem::isGrounded(connector0(), connector1());
1553 }
1554 
acceptsMouseDoubleClickConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1555 bool Wire::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1556 	return true;
1557 }
1558 
acceptsMouseMoveConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1559 bool Wire::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1560 	return true;
1561 }
1562 
acceptsMouseReleaseConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)1563 bool Wire::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
1564 	return true;
1565 }
1566 
setIgnoreSelectionChange(bool ignore)1567 void Wire::setIgnoreSelectionChange(bool ignore) {
1568 	m_ignoreSelectionChange = ignore;
1569 }
1570 
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)1571 bool Wire::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
1572 {
1573 	if (prop.compare("width", Qt::CaseInsensitive) == 0) {
1574 		// don't display width property
1575         hide = true;
1576 		return false;
1577 	}
1578 
1579 	if (prop.compare("color", Qt::CaseInsensitive) == 0) {
1580 		returnProp = tr("color");
1581 		if (canChangeColor()) {
1582 			QComboBox * comboBox = new QComboBox(parent);
1583 			comboBox->setEditable(false);
1584 			comboBox->setEnabled(swappingEnabled);
1585 			comboBox->setObjectName("infoViewComboBox");
1586 
1587 			int ix = 0;
1588 			QString englishCurrColor = colorString();
1589 			foreach(QString transColorName, Wire::colorNames) {
1590 				QString englishColorName = Wire::colorTrans.value(transColorName);
1591 				bool ok = (this->m_viewID != ViewLayer::SchematicView || englishColorName.compare("white", Qt::CaseInsensitive) != 0);
1592 				if (ok) {
1593 					comboBox->addItem(transColorName, QVariant(englishColorName));
1594 					if (englishColorName.compare(englishCurrColor, Qt::CaseInsensitive) == 0) {
1595 						comboBox->setCurrentIndex(ix);
1596 					}
1597 					ix++;
1598 				}
1599 			}
1600 
1601 			connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(colorEntry(const QString &)));
1602 
1603             if (this->hasShadow()) {
1604                 QCheckBox * checkBox = new QCheckBox(tr("Banded"));
1605 		        checkBox->setChecked(m_banded);
1606 		        checkBox->setObjectName("infoViewCheckBox");
1607                 connect(checkBox, SIGNAL(clicked(bool)), this, SLOT(setBandedProp(bool)));
1608 
1609                 QFrame * frame = new QFrame(parent);
1610                 QHBoxLayout * hboxLayout = new QHBoxLayout;
1611                 hboxLayout->addWidget(comboBox);
1612                 hboxLayout->addWidget(checkBox);
1613                 frame->setLayout(hboxLayout);
1614 
1615                 returnWidget = frame;
1616             }
1617             else {
1618 		        returnWidget = comboBox;
1619             }
1620 
1621 			returnValue = comboBox->currentText();
1622 			return true;
1623 		}
1624 		else {
1625 			returnWidget = NULL;
1626 			returnValue = colorString();
1627 			return true;
1628 		}
1629 	}
1630 
1631 	return ItemBase::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide);
1632 }
1633 
colorEntry(const QString & text)1634 void Wire::colorEntry(const QString & text) {
1635 	Q_UNUSED(text);
1636 
1637 	QComboBox * comboBox = qobject_cast<QComboBox *>(sender());
1638 	if (comboBox == NULL) return;
1639 
1640 	QString color = comboBox->itemData(comboBox->currentIndex()).toString();
1641 
1642 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1643 	if (infoGraphicsView != NULL) {
1644 		infoGraphicsView->changeWireColor(color);
1645 	}
1646 }
1647 
hasPartLabel()1648 bool Wire::hasPartLabel() {
1649 
1650 	return false;
1651 }
1652 
isPlural()1653 ItemBase::PluralType Wire::isPlural() {
1654 	return Plural;
1655 }
1656 
checkVisibility(ConnectorItem * onMe,ConnectorItem * onIt,bool connect)1657 void Wire::checkVisibility(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
1658 	if (connect) {
1659 		if (!onIt->attachedTo()->isVisible()) {
1660 			this->setVisible(false);
1661 		}
1662 		else {
1663 			ConnectorItem * other = otherConnector(onMe);
1664 			foreach (ConnectorItem * toConnectorItem, other->connectedToItems()) {
1665 				if (toConnectorItem->attachedToItemType() == ModelPart::Wire) continue;
1666 
1667 				if (!toConnectorItem->attachedTo()->isVisible()) {
1668 					this->setVisible(false);
1669 					break;
1670 				}
1671 			}
1672 		}
1673 	}
1674 }
1675 
canSwitchLayers()1676 bool Wire::canSwitchLayers() {
1677 	return false;
1678 }
1679 
hasPartNumberProperty()1680 bool Wire::hasPartNumberProperty()
1681 {
1682 	return false;
1683 }
1684 
rotationAllowed()1685 bool Wire::rotationAllowed() {
1686 	return false;
1687 }
1688 
rotation45Allowed()1689 bool Wire::rotation45Allowed() {
1690 	return false;
1691 }
1692 
addedToScene(bool temporary)1693 void Wire::addedToScene(bool temporary) {
1694 	ItemBase::addedToScene(temporary);
1695 
1696 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1697 	if (infoGraphicsView == NULL) return;
1698 
1699 	infoGraphicsView->newWire(this);
1700 }
1701 
setConnectorDimensions(double width,double height)1702 void Wire::setConnectorDimensions(double width, double height)
1703 {
1704 	setConnectorDimensionsAux(connector0(), width, height);
1705 	setConnectorDimensionsAux(connector1(), width, height);
1706 }
1707 
setConnectorDimensionsAux(ConnectorItem * connectorItem,double width,double height)1708 void Wire::setConnectorDimensionsAux(ConnectorItem * connectorItem, double width, double height)
1709 {
1710 	QPointF p = connectorItem->rect().center();
1711 	QRectF r(p.x() - (width / 2), p.y() - (height / 2), width, height);
1712 	connectorItem->setRect(r);
1713 	connectorItem->setTerminalPoint(r.center() - r.topLeft());
1714     //debugCompare(connectorItem->attachedTo());
1715 }
1716 
originalConnectorDimensions(double & width,double & height)1717 void Wire::originalConnectorDimensions(double & width, double & height)
1718 {
1719 	width = m_originalConnectorRect.width();
1720 	height = m_originalConnectorRect.height();
1721 }
1722 
isBendpoint(ConnectorItem * connectorItem)1723 bool Wire::isBendpoint(ConnectorItem * connectorItem) {
1724 	return connectorItem->isBendpoint();
1725 }
1726 
hoverStrokeWidth()1727 double Wire::hoverStrokeWidth() {
1728 	return m_hoverStrokeWidth;
1729 }
1730 
getPaintLine()1731 const QLineF & Wire::getPaintLine() {
1732 	return m_line;
1733 }
1734 
1735 /*!
1736     Returns the item's line, or a null line if no line has been set.
1737 
1738     \sa setLine()
1739 */
line() const1740 QLineF Wire::line() const
1741 {
1742     return m_line;
1743 }
1744 
1745 /*!
1746     Sets the item's line to be the given \a line.
1747 
1748     \sa line()
1749 */
setLine(const QLineF & line)1750 void Wire::setLine(const QLineF &line)
1751 {
1752 
1753     //if (line.length() < 0.5) {
1754     //    debugInfo("zero line");
1755     //}
1756 
1757     if (m_line == line)
1758         return;
1759     prepareGeometryChange();
1760     m_line = line;
1761     update();
1762 }
1763 
setLine(double x1,double y1,double x2,double y2)1764 void Wire::setLine(double x1, double y1, double x2, double y2)
1765 {
1766 	setLine(QLineF(x1, y1, x2, y2));
1767 }
1768 
1769 /*!
1770     Returns the item's pen, or a black solid 0-width pen if no pen has
1771     been set.
1772 
1773     \sa setPen()
1774 */
pen() const1775 QPen Wire::pen() const
1776 {
1777     return m_pen;
1778 }
1779 
1780 /*!
1781     Sets the item's pen to \a pen. If no pen is set, the line will be painted
1782     using a black solid 0-width pen.
1783 
1784     \sa pen()
1785 */
setPen(const QPen & pen)1786 void Wire::setPen(const QPen &pen)
1787 {
1788 	if (pen.widthF() != m_pen.widthF()) {
1789 		prepareGeometryChange();
1790 	}
1791     m_pen = pen;
1792     update();
1793 }
1794 
canHaveCurve()1795 bool Wire::canHaveCurve() {
1796 	return m_canHaveCurve && !getRatsnest();
1797 }
1798 
dragCurve(QPointF eventPos,Qt::KeyboardModifiers)1799 void Wire::dragCurve(QPointF eventPos, Qt::KeyboardModifiers)
1800 {
1801 	m_bezier->recalc(eventPos);
1802 }
1803 
changeCurve(const Bezier * bezier)1804 void Wire::changeCurve(const Bezier * bezier)
1805 {
1806 	prepareGeometryChange();
1807 	if (m_bezier == NULL) m_bezier = new Bezier;
1808 	m_bezier->copy(bezier);
1809 	update();
1810 }
1811 
isCurved()1812 bool Wire::isCurved() {
1813 	return (m_bezier != NULL) && !m_bezier->isEmpty();
1814 }
1815 
curve()1816 const Bezier * Wire::curve() {
1817 	return m_bezier;
1818 }
1819 
undoCurve()1820 const Bezier * Wire::undoCurve() {
1821 	return &UndoBezier;
1822 }
1823 
sceneCurve(QPointF offset)1824 QPolygonF Wire::sceneCurve(QPointF offset) {
1825 	QPolygonF poly;
1826 	if (m_bezier == NULL) return poly;
1827 	if (m_bezier->isEmpty()) return poly;
1828 
1829 	poly.append(m_line.p1() + pos() - offset);
1830 	poly.append(m_bezier->cp0() + pos() - offset);
1831 	poly.append(m_bezier->cp1() + pos() - offset);
1832 	poly.append(m_line.p2() + pos() - offset);
1833 	return poly;
1834 }
1835 
hasShadow()1836 bool Wire::hasShadow() {
1837 	if (getRatsnest()) return false;
1838 	if (getTrace()) return false;
1839 	return m_pen.widthF() != m_shadowPen.widthF();
1840 }
1841 
cursorKeyEvent(Qt::KeyboardModifiers modifiers)1842 void Wire::cursorKeyEvent(Qt::KeyboardModifiers modifiers)
1843 {
1844 	if (m_dragEnd || m_dragCurve) return;
1845 
1846 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);;
1847 	if (infoGraphicsView) {
1848 		QPoint p = infoGraphicsView->mapFromGlobal(QCursor::pos());
1849 		QPointF r = infoGraphicsView->mapToScene(p);
1850 		// DebugDialog::debug(QString("got key event %1").arg(keyEvent->modifiers()));
1851 		updateCursor(modifiers);
1852 	}
1853 }
1854 
updateCursor(Qt::KeyboardModifiers modifiers)1855 void Wire::updateCursor(Qt::KeyboardModifiers modifiers)
1856 {
1857 	if (m_connectorHover) {
1858 		return;
1859 	}
1860 
1861 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1862 	bool segment = false;
1863 	int totalConnections = 0;
1864 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1865 		totalConnections += connectorItem->connectionsCount();
1866 	}
1867 	if (totalConnections == 2 && modifiers & altOrMetaModifier()) {
1868 		segment = true;
1869 		foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1870 			if (connectorItem->connectionsCount() != 1) {
1871 				segment = false;
1872 				break;
1873 			}
1874 
1875 			ConnectorItem * toConnectorItem = connectorItem->connectedToItems().at(0);
1876 			if (toConnectorItem->attachedToItemType() != ModelPart::Wire) {
1877 				segment = false;
1878 				break;
1879 			}
1880 		}
1881 	}
1882 
1883 	if (segment) {
1884 		// dragging a segment of wire between bounded by two other wires
1885 		CursorMaster::instance()->addCursor(this, *CursorMaster::RubberbandCursor);
1886 	}
1887 	else if (totalConnections == 0) {
1888 		// only in breadboard view
1889 		CursorMaster::instance()->addCursor(this, *CursorMaster::MoveCursor);
1890 	}
1891 	else if (infoGraphicsView != NULL && infoGraphicsView->curvyWiresIndicated(modifiers)) {
1892 		CursorMaster::instance()->addCursor(this, *CursorMaster::MakeCurveCursor);
1893 	}
1894 	else if (m_displayBendpointCursor) {
1895 		CursorMaster::instance()->addCursor(this, *CursorMaster::NewBendpointCursor);
1896 	}
1897 }
1898 
canChainMultiple()1899 bool Wire::canChainMultiple()
1900 {
1901 	return m_canChainMultiple;
1902 }
1903 
useViewIDForPixmap(ViewLayer::ViewID vid,bool)1904 ViewLayer::ViewID Wire::useViewIDForPixmap(ViewLayer::ViewID vid, bool)
1905 {
1906     if (vid == ViewLayer::BreadboardView) {
1907         return ViewLayer::IconView;
1908     }
1909 
1910     return ViewLayer::UnknownView;
1911 }
1912 
setDisplayBendpointCursor(bool dbc)1913 void Wire::setDisplayBendpointCursor(bool dbc) {
1914 	m_displayBendpointCursor = dbc;
1915 }
1916 
banded()1917 bool Wire::banded() {
1918     return m_banded;
1919 }
1920 
setBanded(bool banded)1921 void Wire::setBanded(bool banded) {
1922     m_banded = banded;
1923 	QList<Wire *> chained;
1924 	QList<ConnectorItem *> ends;
1925 	collectChained(chained, ends);
1926     foreach (Wire * w, chained) {
1927         w->m_banded = banded;
1928         w->update();
1929     }
1930 }
1931 
setBandedProp(bool banded)1932 void Wire::setBandedProp(bool banded) {
1933    	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1934 	if (infoGraphicsView != NULL) {
1935 		infoGraphicsView->setProp(this, "banded", ItemBase::TranslatedPropertyNames.value("banded"), m_banded ? "Yes" : "No", banded  ? "Yes" : "No", true);
1936     }
1937 }
1938 
setProp(const QString & prop,const QString & value)1939 void Wire::setProp(const QString & prop, const QString & value) {
1940 	if (prop.compare("banded", Qt::CaseInsensitive) == 0) {
1941 		setBanded(value == "Yes");
1942 		return;
1943 	}
1944 
1945 	ItemBase::setProp(prop, value);
1946 }
1947 
1948