1 /*******************************************************************
2 
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2015 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: 6998 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-28 13:51:10 +0200 (So, 28. Apr 2013) $
24 
25 ********************************************************************/
26 
27 
28 #include "itembase.h"
29 #include "partfactory.h"
30 #include "../debugdialog.h"
31 #include "../model/modelpart.h"
32 #include "../connectors/connectoritem.h"
33 #include "../connectors/connectorshared.h"
34 #include "../sketch/infographicsview.h"
35 #include "../connectors/connector.h"
36 #include "../connectors/bus.h"
37 #include "partlabel.h"
38 #include "../layerattributes.h"
39 #include "../fsvgrenderer.h"
40 #include "../svg/svgfilesplitter.h"
41 #include "../svg/svgflattener.h"
42 #include "../utils/folderutils.h"
43 #include "../utils/textutils.h"
44 #include "../utils/graphicsutils.h"
45 #include "../utils/cursormaster.h"
46 #include "../utils/clickablelabel.h"
47 #include "../utils/familypropertycombobox.h"
48 #include "../referencemodel/referencemodel.h"
49 
50 #include <QScrollBar>
51 #include <QTimer>
52 #include <QVector>
53 #include <QSet>
54 #include <QSettings>
55 #include <QComboBox>
56 #include <QBitmap>
57 #include <QApplication>
58 #include <QClipboard>
59 #include <qmath.h>
60 
61 /////////////////////////////////
62 
63 static QRegExp NumberMatcher;
64 static QHash<QString, double> NumberMatcherValues;
65 
66 static const double InactiveOpacity = 0.4;
67 
numberValueLessThan(QString v1,QString v2)68 bool numberValueLessThan(QString v1, QString v2)
69 {
70 	return NumberMatcherValues.value(v1, 0) <= NumberMatcherValues.value(v2, 0);
71 }
72 
73 static QSvgRenderer MoveLockRenderer;
74 static QSvgRenderer StickyRenderer;
75 
76 /////////////////////////////////
77 
78 class NameTriple {
79 
80 public:
NameTriple(const QString & _xmlName,const QString & _viewName,const QString & _naturalName)81 	NameTriple(const QString & _xmlName, const QString & _viewName, const QString & _naturalName) {
82 		m_xmlName = _xmlName;
83 		m_viewName = _viewName;
84 		m_naturalName = _naturalName;
85 	}
86 
xmlName()87 	QString & xmlName() {
88 		return m_xmlName;
89 	}
90 
viewName()91 	QString & viewName() {
92 		return m_viewName;
93 	}
94 
naturalName()95 	QString & naturalName() {
96 		return m_naturalName;
97 	}
98 
99 protected:
100 	QString m_xmlName;
101 	QString m_naturalName;
102 	QString m_viewName;
103 };
104 
105 /////////////////////////////////
106 
107 const QString ItemBase::ITEMBASE_FONT_PREFIX = "<font size='2'>";
108 const QString ItemBase::ITEMBASE_FONT_SUFFIX = "</font>";
109 
110 QHash<QString, QString> ItemBase::TranslatedPropertyNames;
111 
112 QPointer<ReferenceModel> ItemBase::TheReferenceModel = NULL;
113 
114 QString ItemBase::PartInstanceDefaultTitle;
115 const QList<ItemBase *> ItemBase::EmptyList;
116 
117 const QColor ItemBase::HoverColor(0,0,0);
118 const double ItemBase::HoverOpacity = .20;
119 const QColor ItemBase::ConnectorHoverColor(0,0,255);
120 const double ItemBase::ConnectorHoverOpacity = .40;
121 
122 const QColor StandardConnectedColor(0, 255, 0);
123 const QColor StandardUnconnectedColor(255, 0, 0);
124 
125 QPen ItemBase::NormalPen(QColor(255,0,0));
126 QPen ItemBase::HoverPen(QColor(0, 0, 255));
127 QPen ItemBase::ConnectedPen(StandardConnectedColor);
128 QPen ItemBase::UnconnectedPen(StandardUnconnectedColor);
129 QPen ItemBase::ChosenPen(QColor(255,0,0));
130 QPen ItemBase::EqualPotentialPen(QColor(255,255,0));
131 
132 QBrush ItemBase::NormalBrush(QColor(255,0,0));
133 QBrush ItemBase::HoverBrush(QColor(0,0,255));
134 QBrush ItemBase::ConnectedBrush(StandardConnectedColor);
135 QBrush ItemBase::UnconnectedBrush(StandardUnconnectedColor);
136 QBrush ItemBase::ChosenBrush(QColor(255,0,0));
137 QBrush ItemBase::EqualPotentialBrush(QColor(255,255,0));
138 
139 const double ItemBase::NormalConnectorOpacity = 0.4;
140 
141 static QHash<QString, QStringList> CachedValues;
142 
143 ///////////////////////////////////////////////////
144 
ItemBase(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu)145 ItemBase::ItemBase( ModelPart* modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu * itemMenu )
146 	: QGraphicsSvgItem()
147 {
148     m_fsvgRenderer = NULL;
149     m_superpart = NULL;
150 	m_acceptsMousePressLegEvent = true;
151 
152     m_squashShape = false;
153 
154     //DebugDialog::debug(QString("itembase %1 %2").arg(id).arg((long) static_cast<QGraphicsItem *>(this), 0, 16));
155 	m_hasRubberBandLeg = m_moveLock = m_hoverEnterSpaceBarWasPressed = m_spaceBarWasPressed = false;
156 
157 	m_moveLockItem = NULL;
158     m_stickyItem = NULL;
159 
160 	m_swappable = m_everVisible = true;
161 
162 	m_rightClickedConnector = NULL;
163 
164 	m_partLabel = NULL;
165 	m_itemMenu = itemMenu;
166 	m_hoverCount = m_connectorHoverCount = m_connectorHoverCount2 = 0;
167 	m_viewID = viewID;
168 	m_modelPart = modelPart;
169 	if (m_modelPart) {
170 		m_modelPart->addViewItem(this);
171 	}
172 	m_id = id;
173 	m_canFlipHorizontal = m_canFlipVertical = m_sticky = m_inRotation = m_inactive = m_layerHidden = m_hidden = false;
174 
175 	setCursor(*CursorMaster::MoveCursor);
176 
177    	m_viewGeometry.set(viewGeometry);
178 	setAcceptHoverEvents ( true );
179 	m_zUninitialized = true;
180 }
181 
~ItemBase()182 ItemBase::~ItemBase() {
183 	//DebugDialog::debug(QString("deleting itembase %1 %2 %3").arg((long) this, 0, 16).arg(m_id).arg((long) m_modelPart, 0, 16));
184 	if (m_partLabel) {
185 		delete m_partLabel;
186 		m_partLabel = NULL;
187 	}
188 
189 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
190 		foreach (ConnectorItem * toConnectorItem, connectorItem->connectedToItems()) {
191 			toConnectorItem->tempRemove(connectorItem, true);
192 		}
193 	}
194 
195 	foreach (ItemBase * itemBase, m_stickyList) {
196 		itemBase->addSticky(this, false);
197 	}
198 
199 	if (m_modelPart != NULL) {
200 		m_modelPart->removeViewItem(this);
201 	}
202 
203     if (m_fsvgRenderer) {
204         delete m_fsvgRenderer;
205     }
206 
207 }
208 
setTooltip()209 void ItemBase::setTooltip() {
210 	if(m_modelPart) {
211 		QString title = instanceTitle();
212 		if(!title.isNull() && !title.isEmpty()) {
213 			setInstanceTitleTooltip(title);
214 		} else {
215 			setDefaultTooltip();
216 		}
217 	} else {
218 		setDefaultTooltip();
219 	}
220 }
221 
removeTooltip()222 void ItemBase::removeTooltip() {
223 	this->setToolTip(___emptyString___);
224 }
225 
zLessThan(ItemBase * & p1,ItemBase * & p2)226 bool ItemBase::zLessThan(ItemBase * & p1, ItemBase * & p2)
227 {
228 	return p1->z() < p2->z();
229 }
230 
getNextID()231 qint64 ItemBase::getNextID() {
232 	return ModelPart::nextIndex() * ModelPart::indexMultiplier;								// make sure we leave room for layerkin inbetween
233 }
234 
getNextID(qint64 index)235 qint64 ItemBase::getNextID(qint64 index) {
236 
237 	qint64 temp = index * ModelPart::indexMultiplier;						// make sure we leave room for layerkin inbetween
238 	ModelPart::updateIndex(index);
239 	return temp;
240 }
241 
size()242 QSizeF ItemBase::size() {
243 	return m_size;
244 }
245 
id() const246 qint64 ItemBase::id() const {
247  	return m_id;
248 }
249 
resetID()250 void ItemBase::resetID() {
251 	m_id = m_modelPart->modelIndex() * ModelPart::indexMultiplier;
252 }
253 
z()254 double ItemBase::z() {
255 	return getViewGeometry().z();
256 }
257 
modelPart()258 ModelPart * ItemBase::modelPart() {
259 	return m_modelPart;
260 }
261 
setModelPart(ModelPart * modelPart)262 void ItemBase::setModelPart(ModelPart * modelPart) {
263 	m_modelPart = modelPart;
264 }
265 
modelPartShared()266 ModelPartShared * ItemBase::modelPartShared() {
267 	if (m_modelPart == NULL) return NULL;
268 
269 	return m_modelPart->modelPartShared();
270 }
271 
initNames()272 void ItemBase::initNames() {
273 	if (NumberMatcher.isEmpty()) {
274 		NumberMatcher.setPattern(QString("(([0-9]+(\\.[0-9]*)?)|\\.[0-9]+)([\\s]*([") + TextUtils::PowerPrefixesString + "]))?");
275 	}
276 
277 	if (TranslatedPropertyNames.count() == 0) {
278 		TranslatedPropertyNames.insert("family", tr("family"));
279 		TranslatedPropertyNames.insert("type", tr("type"));
280 		TranslatedPropertyNames.insert("model", tr("model"));
281 		TranslatedPropertyNames.insert("size", tr("size"));
282 		TranslatedPropertyNames.insert("color", tr("color"));
283 		TranslatedPropertyNames.insert("resistance", tr("resistance"));
284 		TranslatedPropertyNames.insert("capacitance", tr("capacitance"));
285 		TranslatedPropertyNames.insert("inductance", tr("inductance"));
286 		TranslatedPropertyNames.insert("voltage", tr("voltage"));
287 		TranslatedPropertyNames.insert("current", tr("current"));
288 		TranslatedPropertyNames.insert("power", tr("power"));
289 		TranslatedPropertyNames.insert("pin spacing", tr("pin spacing"));
290 		TranslatedPropertyNames.insert("rated power", tr("rated power"));
291 		TranslatedPropertyNames.insert("rated voltage", tr("rated voltage"));
292 		TranslatedPropertyNames.insert("rated current", tr("rated current"));
293 		TranslatedPropertyNames.insert("version", tr("version"));
294 		TranslatedPropertyNames.insert("package", tr("package"));
295 		TranslatedPropertyNames.insert("shape", tr("shape"));
296 		TranslatedPropertyNames.insert("form", tr("form"));
297 		TranslatedPropertyNames.insert("part number", tr("part number"));
298 		TranslatedPropertyNames.insert("maximum resistance", tr("maximum resistance"));
299 		TranslatedPropertyNames.insert("pins", tr("pins"));
300 		TranslatedPropertyNames.insert("spacing", tr("spacing"));
301 		TranslatedPropertyNames.insert("pin spacing", tr("pin spacing"));
302 		TranslatedPropertyNames.insert("frequency", tr("frequency"));
303 		TranslatedPropertyNames.insert("processor", tr("processor"));
304 		TranslatedPropertyNames.insert("variant", tr("variant"));
305 		TranslatedPropertyNames.insert("layers", tr("layers"));
306 		TranslatedPropertyNames.insert("tolerance", tr("tolerance"));
307 		TranslatedPropertyNames.insert("descr", tr("descr"));
308 		TranslatedPropertyNames.insert("filename", tr("filename"));
309 		TranslatedPropertyNames.insert("title", tr("title"));
310 		TranslatedPropertyNames.insert("date", tr("date"));
311 		TranslatedPropertyNames.insert("rev", tr("rev"));
312 		TranslatedPropertyNames.insert("sheet", tr("sheet"));
313 		TranslatedPropertyNames.insert("project", tr("project"));
314 		TranslatedPropertyNames.insert("banded", tr("banded"));
315 		TranslatedPropertyNames.insert("top", tr("top"));
316 		TranslatedPropertyNames.insert("bottom", tr("bottom"));
317 		TranslatedPropertyNames.insert("copper bottom", tr("copper bottom"));
318 		TranslatedPropertyNames.insert("copper top", tr("copper top"));
319 		TranslatedPropertyNames.insert("silkscreen bottom", tr("silkscreen bottom"));
320 		TranslatedPropertyNames.insert("silkscreen top", tr("silkscreen top"));
321 
322 		// TODO: translate more known property names from fzp files and resource xml files
323 
324 	}
325 
326 	PartInstanceDefaultTitle = tr("Part");
327 
328 	QSettings settings;
329 	QString colorName = settings.value("ConnectedColor").toString();
330 	if (!colorName.isEmpty()) {
331 		QColor color;
332 		color.setNamedColor(colorName);
333 		setConnectedColor(color);
334 	}
335 
336 	colorName = settings.value("UnconnectedColor").toString();
337 	if (!colorName.isEmpty()) {
338 		QColor color;
339 		color.setNamedColor(colorName);
340 		setUnconnectedColor(color);
341 	}
342 
343 }
344 
saveInstance(QXmlStreamWriter & streamWriter)345 void ItemBase::saveInstance(QXmlStreamWriter & streamWriter) {
346 	streamWriter.writeStartElement(ViewLayer::viewIDXmlName(m_viewID));
347 	streamWriter.writeAttribute("layer", ViewLayer::viewLayerXmlNameFromID(m_viewLayerID));
348 	if (m_moveLock) {
349 		streamWriter.writeAttribute("locked", "true");
350 	}
351     if (m_superpart) {
352         streamWriter.writeAttribute("superpart", QString::number(m_superpart->modelPart()->modelIndex()));
353     }
354     if (m_viewLayerPlacement == ViewLayer::NewBottom && m_viewID == ViewLayer::PCBView) {
355         streamWriter.writeAttribute("bottom", "true");
356     }
357 
358 	this->saveGeometry();
359 	writeGeometry(streamWriter);
360 	if (m_partLabel) {
361 		m_partLabel->saveInstance(streamWriter);
362 	}
363 
364     QList<ItemBase *> itemBases;
365     itemBases.append(this);
366     itemBases.append(layerKinChief()->layerKin());
367     foreach (ItemBase * itemBase, itemBases) {
368         if (itemBase->layerHidden()) {
369             streamWriter.writeStartElement("layerHidden");
370             streamWriter.writeAttribute("layer", ViewLayer::viewLayerXmlNameFromID(itemBase->viewLayerID()));
371             streamWriter.writeEndElement();
372         }
373     }
374 
375 
376 	bool saveConnectorItems = false;
377 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
378 		if (connectorItem->connectionsCount() > 0 || connectorItem->hasRubberBandLeg() || connectorItem->isGroundFillSeed()) {
379 			saveConnectorItems = true;
380 			break;
381 		}
382 	}
383 
384 	if (saveConnectorItems) {
385 		streamWriter.writeStartElement("connectors");
386 		foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
387 			connectorItem->saveInstance(streamWriter);
388 		}
389 		streamWriter.writeEndElement();
390 	}
391 
392 
393 	streamWriter.writeEndElement();
394 }
395 
writeGeometry(QXmlStreamWriter & streamWriter)396 void ItemBase::writeGeometry(QXmlStreamWriter & streamWriter) {
397 	streamWriter.writeStartElement("geometry");
398 	streamWriter.writeAttribute("z", QString::number(z()));
399 	this->saveInstanceLocation(streamWriter);
400 	// do not write attributes here
401 	streamWriter.writeEndElement();
402 }
403 
getViewGeometry()404 ViewGeometry & ItemBase::getViewGeometry() {
405 	return m_viewGeometry;
406 }
407 
viewID()408 ViewLayer::ViewID ItemBase::viewID() {
409 	return m_viewID;
410 }
411 
viewIDName()412 QString & ItemBase::viewIDName() {
413 	return ViewLayer::viewIDName(m_viewID);
414 }
415 
viewLayerID() const416 ViewLayer::ViewLayerID ItemBase::viewLayerID() const {
417 	return m_viewLayerID;
418 }
419 
setViewLayerID(const QString & layerName,const LayerHash & viewLayers)420 void ItemBase::setViewLayerID(const QString & layerName, const LayerHash & viewLayers) {
421 	//DebugDialog::debug(QString("using z %1").arg(layerName));
422 	setViewLayerID(ViewLayer::viewLayerIDFromXmlString(layerName), viewLayers);
423 }
424 
setViewLayerID(ViewLayer::ViewLayerID viewLayerID,const LayerHash & viewLayers)425 void ItemBase::setViewLayerID(ViewLayer::ViewLayerID viewLayerID, const LayerHash & viewLayers) {
426 	m_viewLayerID = viewLayerID;
427 	if (m_zUninitialized) {
428    		ViewLayer * viewLayer = viewLayers.value(m_viewLayerID);
429    		if (viewLayer != NULL) {
430 			m_zUninitialized = false;
431 			if (!viewLayer->alreadyInLayer(m_viewGeometry.z())) {
432    				m_viewGeometry.setZ(viewLayer->nextZ());
433 			}
434   		}
435   	}
436 
437     //DebugDialog::debug(QString("using z: %1 z:%2 lid:%3").arg(title()).arg(m_viewGeometry.z()).arg(m_viewLayerID) );
438 }
439 
removeLayerKin()440 void ItemBase::removeLayerKin() {
441 }
442 
hoverEnterConnectorItem(QGraphicsSceneHoverEvent *,ConnectorItem *)443 void ItemBase::hoverEnterConnectorItem(QGraphicsSceneHoverEvent * , ConnectorItem * ) {
444 	//DebugDialog::debug(QString("hover enter c %1").arg(instanceTitle()));
445 	hoverEnterConnectorItem();
446 }
447 
hoverEnterConnectorItem()448 void ItemBase::hoverEnterConnectorItem() {
449 	//DebugDialog::debug(QString("hover enter c %1").arg(instanceTitle()));
450 	m_connectorHoverCount++;
451 	hoverUpdate();
452 }
453 
hoverLeaveConnectorItem(QGraphicsSceneHoverEvent *,ConnectorItem *)454 void ItemBase::hoverLeaveConnectorItem(QGraphicsSceneHoverEvent * , ConnectorItem * ) {
455 	hoverLeaveConnectorItem();
456 }
457 
hoverMoveConnectorItem(QGraphicsSceneHoverEvent *,ConnectorItem *)458 void ItemBase::hoverMoveConnectorItem(QGraphicsSceneHoverEvent * , ConnectorItem * ) {
459 }
460 
hoverLeaveConnectorItem()461 void ItemBase::hoverLeaveConnectorItem() {
462 	//DebugDialog::debug(QString("hover leave c %1").arg(instanceTitle()));
463 	m_connectorHoverCount--;
464 	hoverUpdate();
465 }
466 
clearConnectorHover()467 void ItemBase::clearConnectorHover()
468 {
469 	m_connectorHoverCount2 = 0;
470 	hoverUpdate();
471 }
472 
connectorHover(ConnectorItem *,ItemBase *,bool hovering)473 void ItemBase::connectorHover(ConnectorItem *, ItemBase *, bool hovering) {
474 	//DebugDialog::debug(QString("hover c %1 %2").arg(hovering).arg(instanceTitle()));
475 
476 	if (hovering) {
477 		m_connectorHoverCount2++;
478 	}
479 	else {
480 		m_connectorHoverCount2--;
481 	}
482 	// DebugDialog::debug(QString("m_connectorHoverCount2 %1 %2").arg(instanceTitle()).arg(m_connectorHoverCount2));
483 	hoverUpdate();
484 }
485 
hoverUpdate()486 void ItemBase::hoverUpdate() {
487 	this->update();
488 }
489 
mousePressConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)490 void ItemBase::mousePressConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
491 }
492 
mouseDoubleClickConnectorEvent(ConnectorItem *)493 void ItemBase::mouseDoubleClickConnectorEvent(ConnectorItem *) {
494 }
495 
mouseMoveConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)496 void ItemBase::mouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
497 }
498 
mouseReleaseConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)499 void ItemBase::mouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
500 }
501 
filterMousePressConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)502 bool ItemBase::filterMousePressConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
503 	return false;
504 }
505 
acceptsMousePressConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)506 bool ItemBase::acceptsMousePressConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
507 	return true;
508 }
509 
acceptsMousePressLegEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)510 bool ItemBase::acceptsMousePressLegEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
511 	return m_acceptsMousePressLegEvent;
512 }
513 
setAcceptsMousePressLegEvent(bool b)514 void ItemBase::setAcceptsMousePressLegEvent(bool b) {
515 	m_acceptsMousePressLegEvent = b;
516 }
517 
acceptsMouseReleaseConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)518 bool ItemBase::acceptsMouseReleaseConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
519 	return false;
520 }
521 
acceptsMouseDoubleClickConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)522 bool ItemBase::acceptsMouseDoubleClickConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
523 	return false;
524 }
525 
acceptsMouseMoveConnectorEvent(ConnectorItem *,QGraphicsSceneMouseEvent *)526 bool ItemBase::acceptsMouseMoveConnectorEvent(ConnectorItem *, QGraphicsSceneMouseEvent *) {
527 	return false;
528 }
529 
connectionChange(ConnectorItem * onMe,ConnectorItem * onIt,bool connect)530 void ItemBase::connectionChange(ConnectorItem * onMe, ConnectorItem * onIt, bool connect) {
531 	Q_UNUSED(onMe);
532 	Q_UNUSED(onIt);
533 	Q_UNUSED(connect);
534 }
535 
connectedMoved(ConnectorItem * from,ConnectorItem * to,QList<ConnectorItem * > & already)536 void ItemBase::connectedMoved(ConnectorItem * from, ConnectorItem * to,  QList<ConnectorItem *> & already) {
537     Q_UNUSED(from);
538     Q_UNUSED(to);
539     Q_UNUSED(already);
540 }
541 
extractTopLevelItemBase(QGraphicsItem * item)542 ItemBase * ItemBase::extractTopLevelItemBase(QGraphicsItem * item) {
543 	ItemBase * itemBase = dynamic_cast<ItemBase *>(item);
544 	if (itemBase == NULL) return NULL;
545 
546 	if (itemBase->topLevel()) return itemBase;
547 
548 	return NULL;
549 }
550 
topLevel()551 bool ItemBase::topLevel() {
552 	return (this == this->layerKinChief());
553 }
554 
setHidden(bool hide)555 void ItemBase::setHidden(bool hide) {
556 
557 	m_hidden = hide;
558     updateHidden();
559 	foreach (QGraphicsItem * item, childItems()) {
560 		NonConnectorItem * nonconnectorItem = dynamic_cast<NonConnectorItem *>(item);
561 		if (nonconnectorItem == NULL) continue;
562 
563 		nonconnectorItem->setHidden(hide);
564 	}
565 }
566 
setInactive(bool inactivate)567 void ItemBase::setInactive(bool inactivate) {
568 
569 	m_inactive = inactivate;
570 	updateHidden();
571 	foreach (QGraphicsItem * item, childItems()) {
572 		NonConnectorItem * nonconnectorItem = dynamic_cast<NonConnectorItem *>(item);
573 		if (nonconnectorItem == NULL) continue;
574 
575 		nonconnectorItem->setInactive(inactivate);
576 	}
577 }
578 
setLayerHidden(bool layerHidden)579 void ItemBase::setLayerHidden(bool layerHidden) {
580 
581 	m_layerHidden = layerHidden;
582 	updateHidden();
583 	foreach (QGraphicsItem * item, childItems()) {
584 		NonConnectorItem * nonconnectorItem = dynamic_cast<NonConnectorItem *>(item);
585 		if (nonconnectorItem == NULL) continue;
586 
587 		nonconnectorItem->setLayerHidden(layerHidden);
588 	}
589 }
590 
updateHidden()591 void ItemBase::updateHidden() {
592 	setAcceptedMouseButtons(m_hidden || m_inactive || m_layerHidden ? Qt::NoButton : ALLMOUSEBUTTONS);
593 	setAcceptHoverEvents(!(m_hidden || m_inactive || m_layerHidden));
594 	update();
595 }
596 
hidden()597 bool ItemBase::hidden() {
598 	return m_hidden;
599 }
600 
layerHidden()601 bool ItemBase::layerHidden() {
602 	return m_layerHidden;
603 }
604 
inactive()605 bool ItemBase::inactive() {
606 	return m_inactive;
607 }
608 
collectConnectors(ConnectorPairHash & connectorHash,SkipCheckFunction skipCheckFunction)609 void ItemBase::collectConnectors(ConnectorPairHash & connectorHash, SkipCheckFunction skipCheckFunction) {
610 	// Is this modelpart check obsolete?
611 	ModelPart * modelPart = this->modelPart();
612 	if (modelPart == NULL) return;
613 
614 	// collect all the connectorItem pairs
615 
616 	foreach (ConnectorItem * fromConnectorItem, cachedConnectorItems()) {
617 		foreach (ConnectorItem * toConnectorItem, fromConnectorItem->connectedToItems()) {
618 			if (skipCheckFunction && skipCheckFunction(toConnectorItem)) continue;
619 
620 			connectorHash.insert(fromConnectorItem, toConnectorItem);
621 		}
622 
623 		ConnectorItem * crossConnectorItem = fromConnectorItem->getCrossLayerConnectorItem();
624 		if (crossConnectorItem == NULL) continue;
625 
626 		foreach (ConnectorItem * toConnectorItem, crossConnectorItem->connectedToItems()) {
627 			if (skipCheckFunction && skipCheckFunction(toConnectorItem)) continue;
628 
629 			connectorHash.insert(crossConnectorItem, toConnectorItem);
630 		}
631 	}
632 }
633 
findConnectorItemWithSharedID(const QString & connectorID)634 ConnectorItem * ItemBase::findConnectorItemWithSharedID(const QString & connectorID)  {
635     Connector * connector = modelPart()->getConnector(connectorID);
636     if (connector) {
637         return connector->connectorItem(m_viewID);
638 	}
639 
640 	return NULL;
641 }
642 
findConnectorItemWithSharedID(const QString & connectorID,ViewLayer::ViewLayerPlacement viewLayerPlacement)643 ConnectorItem * ItemBase::findConnectorItemWithSharedID(const QString & connectorID, ViewLayer::ViewLayerPlacement viewLayerPlacement)  {
644     ConnectorItem * connectorItem = findConnectorItemWithSharedID(connectorID);
645 	if (connectorItem) {
646 		return connectorItem->chooseFromSpec(viewLayerPlacement);
647 	}
648 
649 	return NULL;
650 }
651 
hoverEnterEvent(QGraphicsSceneHoverEvent * event)652 void ItemBase::hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) {
653 	// debugInfo("itembase hover enter");
654 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
655 	if (infoGraphicsView != NULL && infoGraphicsView->spaceBarIsPressed()) {
656 		m_hoverEnterSpaceBarWasPressed = true;
657 		event->ignore();
658 		return;
659 	}
660 
661 	m_hoverEnterSpaceBarWasPressed = false;
662 	m_hoverCount++;
663     //debugInfo(QString("inc hover %1").arg(m_hoverCount));
664 	hoverUpdate();
665 	if (infoGraphicsView != NULL) {
666 		infoGraphicsView->hoverEnterItem(event, this);
667 	}
668 }
669 
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)670 void ItemBase::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event ) {
671 	//DebugDialog::debug(QString("hover leave %1").arg(instanceTitle()));
672 	if (m_hoverEnterSpaceBarWasPressed) {
673 		event->ignore();
674 		return;
675 	}
676 
677 	m_hoverCount--;
678     //debugInfo(QString("dec hover %1").arg(m_hoverCount));
679 	hoverUpdate();
680 
681 
682 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
683 	if (infoGraphicsView != NULL) {
684 		infoGraphicsView->hoverLeaveItem(event, this);
685 	}
686 }
687 
updateConnections(bool includeRatsnest,QList<ConnectorItem * > & already)688 void ItemBase::updateConnections(bool includeRatsnest, QList<ConnectorItem *> & already) {
689     Q_UNUSED(already)
690     Q_UNUSED(includeRatsnest);
691 }
692 
updateConnections(ConnectorItem * connectorItem,bool includeRatsnest,QList<ConnectorItem * > & already)693 void ItemBase::updateConnections(ConnectorItem * connectorItem, bool includeRatsnest, QList<ConnectorItem *> & already) {
694     if (!already.contains(connectorItem)) {
695         already << connectorItem;
696 	    connectorItem->attachedMoved(includeRatsnest, already);
697     }
698     else {
699         connectorItem->debugInfo("already");
700     }
701 }
702 
title()703 const QString & ItemBase::title() {
704     if (m_modelPart == NULL) return ___emptyString___;
705 
706     return m_modelPart->title();
707 }
708 
constTitle() const709 const QString & ItemBase::constTitle() const {
710     if (m_modelPart == NULL) return ___emptyString___;
711 
712     return m_modelPart->title();
713 }
714 
spice() const715 const QString & ItemBase::spice() const {
716 	if (m_modelPart == NULL) return ___emptyString___;
717 
718 	return m_modelPart->spice();
719 }
720 
spiceModel() const721 const QString & ItemBase::spiceModel() const {
722 	if (m_modelPart == NULL) return ___emptyString___;
723 
724 	return m_modelPart->spiceModel();
725 }
726 
getRatsnest()727 bool ItemBase::getRatsnest() {
728 	return m_viewGeometry.getRatsnest();
729 }
730 
buses()731 QList<Bus *> ItemBase::buses() {
732 	QList<Bus *> busList;
733 	if (m_modelPart == NULL) return busList;
734 
735 	foreach (Bus * bus, m_modelPart->buses().values()) {
736 		busList.append(bus);
737 	}
738 
739 	return busList;
740 }
741 
busConnectorItems(class Bus * bus,ConnectorItem * fromConnectorItem,QList<class ConnectorItem * > & items)742 void ItemBase::busConnectorItems(class Bus * bus, ConnectorItem * fromConnectorItem, QList<class ConnectorItem *> & items) {
743     Q_UNUSED(fromConnectorItem)
744 
745 	if (bus == NULL) return;
746 
747 	foreach (Connector * connector, bus->connectors()) {
748 		foreach (ConnectorItem * connectorItem, connector->viewItems()) {
749 			if (connectorItem != NULL) {
750 				//connectorItem->debugInfo(QString("on the bus %1").arg((long) connector, 0, 16));
751 				if (connectorItem->attachedTo() == this) {
752 					items.append(connectorItem);
753 				}
754 			}
755 		}
756 	}
757 
758     if (m_superpart || m_subparts.count() > 0) {
759 	    Connector * connector = bus->subConnector();
760         if (connector) {
761 		    foreach (ConnectorItem * connectorItem, connector->viewItems()) {
762 			    if (connectorItem != NULL) {
763 				    //connectorItem->debugInfo(QString("on the bus %1").arg((long) connector, 0, 16));
764 				    if (connectorItem->attachedToViewID() == m_viewID) {
765 					    items.append(connectorItem);
766 				    }
767 			    }
768 		    }
769         }
770     }
771 
772 
773     /*
774     if (items.count() > 0) {
775         fromConnectorItem->debugInfo("bus");
776         foreach (ConnectorItem * ci, items) {
777             ci->debugInfo("\t");
778         }
779     }
780     */
781 }
782 
itemType() const783 int ItemBase::itemType() const
784 {
785 	if (m_modelPart == NULL) return ModelPart::Unknown;
786 
787 	return m_modelPart->itemType();
788 }
789 
inHover()790 bool ItemBase::inHover() {
791 	return (!m_inactive && (m_connectorHoverCount > 0 || m_hoverCount > 0 || m_connectorHoverCount2 > 0));
792 }
793 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)794 void ItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
795 	if (inHover()) {
796 		//DebugDialog::debug(QString("chc:%1 hc:%2 chc2:%3").arg(m_connectorHoverCount).arg(m_hoverCount).arg(m_connectorHoverCount2));
797 		layerKinChief()->paintHover(painter, option, widget);
798 	}
799 	//else {
800 		//DebugDialog::debug("no hover");
801 	//}
802 
803 	if (m_inactive) {
804 		painter->save();
805 		painter->setOpacity(InactiveOpacity);
806 	}
807 
808 	paintBody(painter, option, widget);
809 
810 	if (option->state & QStyle::State_Selected) {
811 		layerKinChief()->paintSelected(painter, option, widget);
812     }
813 
814 	if (m_inactive) {
815 		painter->restore();
816 	}
817 }
818 
paintBody(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)819 void ItemBase::paintBody(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
820 {
821 	Q_UNUSED(option);
822 	Q_UNUSED(widget);
823 
824 	// Qt's SVG renderer's defaultSize is not correct when the svg has a fractional pixel size
825 	fsvgRenderer()->render(painter, boundingRectWithoutLegs());
826 }
827 
paintHover(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)828 void ItemBase::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
829 {
830 	paintHover(painter, option, widget, hoverShape());
831 }
832 
paintSelected(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)833 void ItemBase::paintSelected(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
834 {
835 	Q_UNUSED(widget);
836 	GraphicsUtils::qt_graphicsItem_highlightSelected(painter, option, boundingRect(), hoverShape());
837 }
838 
paintHover(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget,const QPainterPath & shape)839 void ItemBase::paintHover(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, const QPainterPath & shape)
840 {
841 	Q_UNUSED(widget);
842 	Q_UNUSED(option);
843 	painter->save();
844 	if (m_connectorHoverCount > 0 || m_connectorHoverCount2 > 0) {
845 		painter->setOpacity(ConnectorHoverOpacity);
846 		painter->fillPath(shape, QBrush(ConnectorHoverColor));
847 	}
848 	else {
849 		painter->setOpacity(HoverOpacity);
850 		painter->fillPath(shape, QBrush(HoverColor));
851 	}
852 	painter->restore();
853 }
854 
mousePressEvent(QGraphicsSceneMouseEvent * event)855 void ItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event) {
856 	InfoGraphicsView *infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
857 	if (infoGraphicsView != NULL && infoGraphicsView->spaceBarIsPressed()) {
858 		event->ignore();
859 		return;
860 	}
861 
862 	//scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
863 	//setCacheMode(QGraphicsItem::DeviceCoordinateCache);
864 	QGraphicsSvgItem::mousePressEvent(event);
865 }
866 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)867 void ItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
868 {
869 	m_rightClickedConnector = NULL;
870 	// calling parent class so that multiple selection will work
871 	// haven't yet discovered any nasty side-effect
872 	QGraphicsSvgItem::mouseReleaseEvent(event);
873 
874 	//scene()->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
875 	// setCacheMode(QGraphicsItem::NoCache);
876 
877 }
878 
mouseMoveEvent(QGraphicsSceneMouseEvent *)879 void ItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *)
880 {
881 }
882 
setItemPos(QPointF & loc)883 void ItemBase::setItemPos(QPointF & loc) {
884 	setPos(loc);
885 }
886 
stickyEnabled()887 bool ItemBase::stickyEnabled() {
888 	return true;
889 }
890 
isSticky()891 bool ItemBase::isSticky() {
892 	return isBaseSticky() && isLocalSticky();
893 }
894 
895 
isBaseSticky()896 bool ItemBase::isBaseSticky() {
897 	return m_sticky;   // to cancel sticky return false;
898 }
899 
setSticky(bool s)900 void ItemBase::setSticky(bool s)
901 {
902 	m_sticky = s;
903 }
904 
isLocalSticky()905 bool ItemBase::isLocalSticky() {
906     if (layerKinChief() != this) {
907         return layerKinChief()->isLocalSticky();
908     }
909     QString stickyVal = modelPart()->localProp("sticky").toString();
910 	// return (stickyVal.compare("false") != 0);       // defaults to true
911 	return (stickyVal.compare("true") == 0);           // defaults to false
912 }
913 
setLocalSticky(bool s)914 void ItemBase::setLocalSticky(bool s)
915 {
916     // dirty the window?
917     // undo command?
918     if (layerKinChief() != this) {
919         layerKinChief()->setLocalSticky(s);
920         return;
921     }
922 
923     modelPart()->setLocalProp("sticky", s ? "true" : "false");
924 
925 	if (s) {
926         if (m_stickyItem == NULL) {
927 		    if (!StickyRenderer.isValid()) {
928 			    QString fn(":resources/images/part_sticky.svg");
929 			    bool success = StickyRenderer.load(fn);
930                 Q_UNUSED(success);
931 			    //DebugDialog::debug(QString("sticky load success %1").arg(success));
932 		    }
933 
934 		    m_stickyItem = new QGraphicsSvgItem();
935 		    m_stickyItem->setAcceptHoverEvents(false);
936 		    m_stickyItem->setAcceptedMouseButtons(Qt::NoButton);
937 		    m_stickyItem->setSharedRenderer(&StickyRenderer);
938 		    m_stickyItem->setPos(m_moveLockItem == NULL ? 0 : m_moveLockItem->boundingRect().width() + 1, 0);
939 		    m_stickyItem->setZValue(-99999);
940 		    m_stickyItem->setParentItem(this);
941 		    m_stickyItem->setVisible(true);
942         }
943 	}
944 	else {
945 		if (m_stickyItem) {
946 			delete m_stickyItem;
947 			m_stickyItem = NULL;
948 		}
949 	}
950 
951 	update();
952 }
953 
addSticky(ItemBase * stickyBase,bool stickem)954 void ItemBase::addSticky(ItemBase * stickyBase, bool stickem) {
955 	stickyBase = stickyBase->layerKinChief();
956 	//this->debugInfo(QString("add sticky %1:").arg(stickem));
957 	//sticky->debugInfo(QString("  to"));
958 	if (stickem) {
959 		if (!isBaseSticky()) {
960 			foreach (ItemBase * oldstickingTo, m_stickyList.values()) {
961 				if (oldstickingTo == stickyBase) continue;
962 
963 				oldstickingTo->addSticky(this, false);
964 			}
965 			m_stickyList.clear();
966 		}
967 		m_stickyList.insert(stickyBase->id(), stickyBase);
968 	}
969 	else {
970 		m_stickyList.remove(stickyBase->id());
971 	}
972 }
973 
974 
stickingTo()975 ItemBase * ItemBase::stickingTo() {
976 	if (isBaseSticky()) return NULL;
977 
978 	if (m_stickyList.count() < 1) return NULL;
979 
980 	if (m_stickyList.count() > 1) {
981 		DebugDialog::debug(QString("error: sticky list > 1 %1").arg(title()));
982 	}
983 
984 	return *m_stickyList.begin();
985 }
986 
stickyList()987 QList< QPointer<ItemBase> > ItemBase::stickyList() {
988 	return m_stickyList.values();
989 }
990 
alreadySticking(ItemBase * itemBase)991 bool ItemBase::alreadySticking(ItemBase * itemBase) {
992 	return m_stickyList.value(itemBase->layerKinChief()->id(), NULL) != NULL;
993 }
994 
newConnectorItem(Connector * connector)995 ConnectorItem* ItemBase::newConnectorItem(Connector *connector)
996 {
997 	return newConnectorItem(this, connector);
998 }
999 
newConnectorItem(ItemBase * layerKin,Connector * connector)1000 ConnectorItem* ItemBase::newConnectorItem(ItemBase * layerKin, Connector *connector)
1001 {
1002 	return new ConnectorItem(connector, layerKin);
1003 }
1004 
anyConnectorItem()1005 ConnectorItem * ItemBase::anyConnectorItem() {
1006 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1007 		return connectorItem;
1008 	}
1009 
1010 	return NULL;
1011 }
1012 
1013 
instanceTitle() const1014 const QString & ItemBase::instanceTitle() const {
1015 	if (m_modelPart) {
1016 		return m_modelPart->instanceTitle();
1017 	}
1018 	return ___emptyString___;
1019 }
1020 
setInstanceTitle(const QString & title,bool initial)1021 void ItemBase::setInstanceTitle(const QString &title, bool initial) {
1022 	setInstanceTitleAux(title, initial);
1023 	if (m_partLabel) {
1024 		m_partLabel->setPlainText(title);
1025 	}
1026 }
1027 
updatePartLabelInstanceTitle()1028 void ItemBase::updatePartLabelInstanceTitle() {
1029 	if (m_partLabel) {
1030 		m_partLabel->setPlainText(instanceTitle());
1031 	}
1032 }
1033 
setInstanceTitleAux(const QString & title,bool initial)1034 void ItemBase::setInstanceTitleAux(const QString &title, bool initial)
1035 {
1036 	if (m_modelPart) {
1037 		m_modelPart->setInstanceTitle(title, initial);
1038 	}
1039 	setInstanceTitleTooltip(title);
1040 
1041 //	InfoGraphicsView *infographics = InfoGraphicsView::getInfoGraphicsView(this);
1042 //	if (infographics != NULL) {
1043 //		infographics->setItemTooltip(this, title);
1044 //	}
1045 }
1046 
label()1047 QString ItemBase::label() {
1048 	if(m_modelPart) {
1049 		return m_modelPart->label();
1050 	}
1051 	return ___emptyString___;
1052 }
1053 
updateTooltip()1054 void ItemBase::updateTooltip() {
1055 	setInstanceTitleTooltip(instanceTitle());
1056 }
1057 
setInstanceTitleTooltip(const QString & text)1058 void ItemBase::setInstanceTitleTooltip(const QString &text) {
1059 	setToolTip("<b>"+text+"</b><br></br>" + ITEMBASE_FONT_PREFIX + title()+ ITEMBASE_FONT_SUFFIX);
1060 }
1061 
setDefaultTooltip()1062 void ItemBase::setDefaultTooltip() {
1063 	if (m_modelPart) {
1064 		if (m_viewID == ViewLayer::IconView) {
1065 			QString base = ITEMBASE_FONT_PREFIX + "%1" + ITEMBASE_FONT_SUFFIX;
1066 			if(m_modelPart->itemType() != ModelPart::Wire) {
1067 				this->setToolTip(base.arg(m_modelPart->title()));
1068 			} else {
1069 				this->setToolTip(base.arg(m_modelPart->title() + " (" + m_modelPart->moduleID() + ")"));
1070 			}
1071 			return;
1072 		}
1073 
1074 		QString title = ItemBase::PartInstanceDefaultTitle;
1075 		QString inst = instanceTitle();
1076 		if(!inst.isNull() && !inst.isEmpty()) {
1077 			title = inst;
1078 		} else {
1079 			QString defaultTitle = label();
1080 			if(!defaultTitle.isNull() && !defaultTitle.isEmpty()) {
1081 				title = defaultTitle;
1082 			}
1083 		}
1084 		ensureUniqueTitle(title, false);
1085 		setInstanceTitleTooltip(instanceTitle());
1086 	}
1087 }
1088 
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)1089 void ItemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
1090 {
1091 	if ((acceptedMouseButtons() & Qt::RightButton) == 0) {
1092 		event->ignore();
1093 		return;
1094 	}
1095 
1096 	if (m_hidden || m_inactive || m_layerHidden) {
1097 		event->ignore();
1098 		return;
1099 	}
1100 
1101     scene()->clearSelection();
1102     setSelected(true);
1103 
1104     if (m_itemMenu != NULL) {
1105 		m_rightClickedConnector = NULL;
1106 		foreach (QGraphicsItem * item, scene()->items(event->scenePos())) {
1107 			ConnectorItem * connectorItem = dynamic_cast<ConnectorItem *>(item);
1108 			if (connectorItem == NULL) continue;
1109 
1110 			if (connectorItem->attachedTo() == this) {
1111 				m_rightClickedConnector = connectorItem;
1112 				break;
1113 			}
1114 		}
1115 
1116      	m_itemMenu->exec(event->screenPos());
1117 	}
1118 }
1119 
hasConnectors()1120 bool ItemBase::hasConnectors() {
1121 	return cachedConnectorItems().count() > 0;
1122 }
1123 
hasNonConnectors()1124 bool ItemBase::hasNonConnectors() {
1125 	foreach (QGraphicsItem * childItem, childItems()) {
1126 		if (dynamic_cast<NonConnectorItem *>(childItem) != NULL) return true;
1127 	}
1128 
1129 	return false;
1130 }
1131 
canFlip(Qt::Orientations orientations)1132 bool ItemBase::canFlip(Qt::Orientations orientations) {
1133 	bool result = true;
1134 	if (orientations & Qt::Horizontal) {
1135 		result = result && m_canFlipHorizontal;
1136 	}
1137 	if (orientations & Qt::Vertical) {
1138 		result = result && m_canFlipVertical;
1139 	}
1140 	return result;
1141 }
1142 
canFlipHorizontal()1143 bool ItemBase::canFlipHorizontal() {
1144 	return m_canFlipHorizontal && !m_moveLock;
1145 }
1146 
setCanFlipHorizontal(bool cf)1147 void ItemBase::setCanFlipHorizontal(bool cf) {
1148 	m_canFlipHorizontal = cf;
1149 }
1150 
canFlipVertical()1151 bool ItemBase::canFlipVertical() {
1152 	return m_canFlipVertical && !m_moveLock;
1153 }
1154 
setCanFlipVertical(bool cf)1155 void ItemBase::setCanFlipVertical(bool cf) {
1156 	m_canFlipVertical = cf;
1157 }
1158 
rotationAllowed()1159 bool ItemBase::rotationAllowed() {
1160 	return !m_moveLock;
1161 }
1162 
rotation45Allowed()1163 bool ItemBase::rotation45Allowed() {
1164 	return !m_moveLock;
1165 }
1166 
freeRotationAllowed()1167 bool ItemBase::freeRotationAllowed() {
1168 	return false;
1169 }
1170 
clearModelPart()1171 void ItemBase::clearModelPart() {
1172 	m_modelPart = NULL;
1173 }
1174 
hidePartLabel()1175 void ItemBase::hidePartLabel()
1176 {
1177 	InfoGraphicsView *infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1178 	if (infoGraphicsView) infoGraphicsView->hidePartLabel(this);
1179 }
1180 
showPartLabel(bool showIt,ViewLayer * viewLayer)1181 void ItemBase::showPartLabel(bool showIt, ViewLayer* viewLayer) {
1182 	if (m_partLabel) {
1183 		m_partLabel->showLabel(showIt, viewLayer);
1184 	}
1185 }
1186 
partLabelChanged(const QString & newText)1187 void ItemBase::partLabelChanged(const QString & newText) {
1188 	// sent from part label after inline edit
1189 	InfoGraphicsView *infographics = InfoGraphicsView::getInfoGraphicsView(this);
1190 	QString oldText = modelPart()->instanceTitle();
1191 	setInstanceTitleAux(newText, false);
1192 	if (infographics != NULL) {
1193 		infographics->partLabelChanged(this, oldText, newText);
1194 	}
1195 }
1196 
isPartLabelVisible()1197 bool ItemBase::isPartLabelVisible() {
1198 	if (m_partLabel == NULL) return false;
1199 	if (!hasPartLabel()) return false;
1200 	if (!m_partLabel->initialized()) return false;
1201 
1202 	return m_partLabel->isVisible();
1203 }
1204 
clearPartLabel()1205 void ItemBase::clearPartLabel() {
1206 	m_partLabel = NULL;
1207 }
1208 
restorePartLabel(QDomElement & labelGeometry,ViewLayer::ViewLayerID viewLayerID)1209 void ItemBase::restorePartLabel(QDomElement & labelGeometry, ViewLayer::ViewLayerID viewLayerID)
1210 {
1211 	if (m_partLabel) {
1212 		m_partLabel->setPlainText(instanceTitle());
1213 		if (!labelGeometry.isNull()) {
1214 			m_partLabel->restoreLabel(labelGeometry, viewLayerID);
1215 			//m_partLabel->setPlainText(instanceTitle());
1216 		}
1217 	}
1218 }
1219 
movePartLabel(QPointF newPos,QPointF newOffset)1220 void ItemBase::movePartLabel(QPointF newPos, QPointF newOffset) {
1221 	if (m_partLabel) {
1222 		m_partLabel->moveLabel(newPos, newOffset);
1223 	}
1224 }
1225 
partLabelSetHidden(bool hide)1226 void ItemBase::partLabelSetHidden(bool hide) {
1227 	if (m_partLabel) {
1228 		m_partLabel->setHidden(hide);
1229 	}
1230 }
1231 
partLabelMoved(QPointF oldPos,QPointF oldOffset,QPointF newPos,QPointF newOffset)1232 void ItemBase::partLabelMoved(QPointF oldPos, QPointF oldOffset, QPointF newPos, QPointF newOffset) {
1233 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1234 	if (infoGraphicsView != NULL) {
1235 		infoGraphicsView->partLabelMoved(this, oldPos, oldOffset, newPos, newOffset);
1236 	}
1237 }
1238 
rotateFlipPartLabel(double degrees,Qt::Orientations orientation)1239 void ItemBase::rotateFlipPartLabel(double degrees, Qt::Orientations orientation)
1240 {
1241 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1242 	if (infoGraphicsView != NULL) {
1243 		infoGraphicsView->rotateFlipPartLabel(this, degrees, orientation);
1244 	}
1245 }
1246 
1247 
doRotateFlipPartLabel(double degrees,Qt::Orientations orientation)1248 void ItemBase::doRotateFlipPartLabel(double degrees, Qt::Orientations orientation)
1249 {
1250 	if (m_partLabel) {
1251 		m_partLabel->rotateFlipLabel(degrees, orientation);
1252 	}
1253 }
1254 
isSwappable()1255 bool ItemBase::isSwappable() {
1256 	return m_swappable;
1257 }
1258 
setSwappable(bool swappable)1259 void ItemBase::setSwappable(bool swappable) {
1260 	m_swappable = swappable;
1261 }
1262 
ensureUniqueTitle(const QString & title,bool force)1263 void ItemBase::ensureUniqueTitle(const QString & title, bool force) {
1264 	if (force || instanceTitle().isEmpty() || instanceTitle().isNull()) {
1265 		setInstanceTitle(modelPart()->getNextTitle(title), true);
1266 	}
1267 }
1268 
itemChange(QGraphicsItem::GraphicsItemChange change,const QVariant & value)1269 QVariant ItemBase::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant & value)
1270 {
1271 	switch (change) {
1272 		case QGraphicsItem::ItemSelectedChange:
1273 			if (m_partLabel) {
1274 				m_partLabel->ownerSelected(value.toBool());
1275 			}
1276 
1277 			break;
1278 		default:
1279 			break;
1280 	}
1281 
1282 	return QGraphicsSvgItem::itemChange(change, value);
1283 }
1284 
cleanup()1285 void ItemBase::cleanup() {
1286 }
1287 
layerKin()1288 const QList<ItemBase *> & ItemBase::layerKin() {
1289 	return EmptyList;
1290 }
1291 
layerKinChief()1292 ItemBase * ItemBase::layerKinChief() {
1293 	return this;
1294 }
1295 
rotateItem(double degrees,bool includeRatsnest)1296 void ItemBase::rotateItem(double degrees, bool includeRatsnest) {
1297 	//this->debugInfo(QString("\trotating item %1").arg(degrees));
1298 	transformItem(QTransform().rotate(degrees), includeRatsnest);
1299 }
1300 
flipItem(Qt::Orientations orientation)1301 void ItemBase::flipItem(Qt::Orientations orientation) {
1302 	int xScale; int yScale;
1303 	if(orientation == Qt::Vertical) {
1304 		xScale = 1;
1305 		yScale = -1;
1306 	} else if(orientation == Qt::Horizontal) {
1307 		xScale = -1;
1308 		yScale = 1;
1309 	}
1310 	else {
1311 		return;
1312 	}
1313 
1314 	transformItem(QTransform().scale(xScale,yScale), false);
1315 }
1316 
transformItem(const QTransform & currTransf,bool includeRatsnest)1317 void ItemBase::transformItem(const QTransform & currTransf, bool includeRatsnest) {
1318     //debugInfo("transform item " + TextUtils::svgMatrix(currTransf));
1319 
1320     QTransform trns = getViewGeometry().transform();
1321     //debugInfo("\t" + TextUtils::svgMatrix(trns));
1322 
1323 
1324 
1325 	if (m_hasRubberBandLeg) {
1326 		prepareGeometryChange();
1327 	}
1328 	QRectF rect = this->boundingRectWithoutLegs();
1329 
1330     //debugInfo(QString("\t bounding rect w:%1, h:%2").arg(rect.width()).arg(rect.height()));
1331 	double x = rect.width() / 2.0;
1332 	double y = rect.height() / 2.0;
1333 	QTransform transf = QTransform().translate(-x, -y) * currTransf * QTransform().translate(x, y);
1334 	getViewGeometry().setTransform(getViewGeometry().transform()*transf);
1335 	this->setTransform(getViewGeometry().transform());
1336 	if (!m_hasRubberBandLeg) {
1337         QList<ConnectorItem *> already;
1338 		updateConnections(includeRatsnest, already);
1339 	}
1340 
1341     trns = getViewGeometry().transform();
1342     //debugInfo("\t" + TextUtils::svgMatrix(trns));
1343 
1344 	update();
1345 }
1346 
transformItem2(const QMatrix & matrix)1347 void ItemBase::transformItem2(const QMatrix & matrix) {
1348 	QTransform transform(matrix);
1349 	transformItem(transform, false);
1350 }
1351 
collectWireConnectees(QSet<class Wire * > & wires)1352 void ItemBase::collectWireConnectees(QSet<class Wire *> & wires) {
1353 	Q_UNUSED(wires);
1354 }
1355 
collectFemaleConnectees(QSet<ItemBase * > & items)1356 bool ItemBase::collectFemaleConnectees(QSet<ItemBase *> & items) {
1357 	Q_UNUSED(items);
1358 	return false;			// means no male connectors
1359 }
1360 
prepareGeometryChange()1361 void ItemBase::prepareGeometryChange() {
1362 	// made public so it can be invoked from outside ItemBase class
1363 
1364 	//debugInfo("itembase prepare geometry change");
1365 	QGraphicsSvgItem::prepareGeometryChange();
1366 }
1367 
saveLocAndTransform(QXmlStreamWriter & streamWriter)1368 void ItemBase::saveLocAndTransform(QXmlStreamWriter & streamWriter)
1369 {
1370 	streamWriter.writeAttribute("x", QString::number(m_viewGeometry.loc().x()));
1371 	streamWriter.writeAttribute("y", QString::number(m_viewGeometry.loc().y()));
1372 	GraphicsUtils::saveTransform(streamWriter, m_viewGeometry.transform());
1373 }
1374 
setUpImage(ModelPart * modelPart,LayerAttributes & layerAttributes)1375 FSvgRenderer * ItemBase::setUpImage(ModelPart * modelPart, LayerAttributes & layerAttributes)
1376 {
1377     // at this point "this" has not yet been added to the scene, so one cannot get back to the InfoGraphicsView
1378 
1379     ModelPartShared * modelPartShared = modelPart->modelPartShared();
1380 
1381 	if (modelPartShared == NULL) {
1382 		layerAttributes.error = tr("model part problem");
1383 		return NULL;
1384 	}
1385 
1386     //if (modelPartShared->moduleID() == "df9d072afa2b594ac67b60b4153ff57b_29" && viewID == ViewLayer::PCBView) {
1387     //    DebugDialog::debug("here i am now");
1388     //}
1389 
1390 	//DebugDialog::debug(QString("setting z %1 %2")
1391 		//.arg(this->z())
1392 		//.arg(ViewLayer::viewLayerNameFromID(viewLayerID))  );
1393 
1394 
1395 	//DebugDialog::debug(QString("set up image elapsed (1) %1").arg(t.elapsed()) );
1396 	QString filename = PartFactory::getSvgFilename(modelPart, modelPartShared->imageFileName(layerAttributes.viewID, layerAttributes.viewLayerID), true, true);
1397 
1398 //#ifndef QT_NO_DEBUG
1399 	//DebugDialog::debug(QString("set up image elapsed (2) %1").arg(t.elapsed()) );
1400 //#endif
1401 
1402 	if (filename.isEmpty()) {
1403 		//QString deleteme = modelPartShared->domDocument()->toString();
1404 		layerAttributes.error = tr("file for %1 %2 not found").arg(modelPartShared->title()).arg(modelPartShared->moduleID());
1405         return NULL;
1406 	}
1407 
1408     LoadInfo loadInfo;
1409 	switch (layerAttributes.viewID) {
1410 		case ViewLayer::PCBView:
1411 			loadInfo.colorElementID = ViewLayer::viewLayerXmlNameFromID(layerAttributes.viewLayerID);
1412 			switch (layerAttributes.viewLayerID) {
1413 				case ViewLayer::Copper0:
1414 					modelPartShared->connectorIDs(layerAttributes.viewID, layerAttributes.viewLayerID, loadInfo.connectorIDs, loadInfo.terminalIDs, loadInfo.legIDs);
1415 					loadInfo.setColor = ViewLayer::Copper0Color;
1416                     loadInfo.findNonConnectors = loadInfo.parsePaths = true;
1417 					break;
1418 				case ViewLayer::Copper1:
1419 					modelPartShared->connectorIDs(layerAttributes.viewID, layerAttributes.viewLayerID, loadInfo.connectorIDs, loadInfo.terminalIDs, loadInfo.legIDs);
1420 					loadInfo.setColor = ViewLayer::Copper1Color;
1421                     loadInfo.findNonConnectors = loadInfo.parsePaths = true;
1422 					break;
1423 				case ViewLayer::Silkscreen1:
1424 					loadInfo.setColor = ViewLayer::Silkscreen1Color;
1425 					break;
1426 				case ViewLayer::Silkscreen0:
1427 					loadInfo.setColor = ViewLayer::Silkscreen0Color;
1428 					break;
1429 				default:
1430 					break;
1431 			}
1432 			break;
1433 		case ViewLayer::BreadboardView:
1434 			modelPartShared->connectorIDs(layerAttributes.viewID, layerAttributes.viewLayerID, loadInfo.connectorIDs, loadInfo.terminalIDs, loadInfo.legIDs);
1435 			break;
1436         default:
1437             // don't need connectorIDs() for schematic view since these parts do not have bendable legs or connectors with drill holes
1438             break;
1439 	}
1440 
1441 	FSvgRenderer * newRenderer = new FSvgRenderer();
1442 	QDomDocument flipDoc;
1443 	getFlipDoc(modelPart, filename, layerAttributes.viewLayerID, layerAttributes.viewLayerPlacement, flipDoc, layerAttributes.orientation);
1444     QByteArray bytesToLoad;
1445     if (layerAttributes.viewLayerID == ViewLayer::Schematic) {
1446         bytesToLoad = SvgFileSplitter::hideText(filename);
1447     }
1448     else if (layerAttributes.viewLayerID == ViewLayer::SchematicText) {
1449         bool hasText = false;
1450         bytesToLoad = SvgFileSplitter::showText(filename, hasText);
1451         if (!hasText) {
1452             return NULL;
1453         }
1454     }
1455 	else if ((layerAttributes.viewID != ViewLayer::IconView) && modelPartShared->hasMultipleLayers(layerAttributes.viewID)) {
1456         QString layerName = ViewLayer::viewLayerXmlNameFromID(layerAttributes.viewLayerID);
1457 		// need to treat create "virtual" svg file for each layer
1458 		SvgFileSplitter svgFileSplitter;
1459 		bool result;
1460 		if (flipDoc.isNull()) {
1461 			result = svgFileSplitter.split(filename, layerName);
1462 		}
1463 		else {
1464 			QString f = flipDoc.toString();
1465 			result = svgFileSplitter.splitString(f, layerName);
1466 		}
1467 		if (result) {
1468             bytesToLoad = svgFileSplitter.byteArray();
1469 		}
1470 	}
1471 	else {
1472 		// only one layer, just load it directly
1473 		if (flipDoc.isNull()) {
1474             QFile file(filename);
1475             file.open(QFile::ReadOnly);
1476             bytesToLoad = file.readAll();
1477 		}
1478 		else {
1479             bytesToLoad = flipDoc.toByteArray();
1480 		}
1481     }
1482 
1483     QByteArray resultBytes;
1484     if (!bytesToLoad.isEmpty()) {
1485         if (makeLocalModifications(bytesToLoad, filename)) {
1486             if (layerAttributes.viewLayerID == ViewLayer::Schematic) {
1487                 bytesToLoad = SvgFileSplitter::hideText2(bytesToLoad);
1488             }
1489             else if (layerAttributes.viewLayerID == ViewLayer::SchematicText) {
1490                 bool hasText;
1491                 bytesToLoad = SvgFileSplitter::showText2(bytesToLoad, hasText);
1492             }
1493         }
1494 
1495         loadInfo.filename = filename;
1496         resultBytes = newRenderer->loadSvg(bytesToLoad, loadInfo);
1497     }
1498 
1499     layerAttributes.setLoaded(resultBytes);
1500 
1501 #ifndef QT_NO_DEBUG
1502 //	DebugDialog::debug(QString("set up image elapsed (2.3) %1").arg(t.elapsed()) );
1503 #endif
1504 
1505 	if (resultBytes.isEmpty()) {
1506 		delete newRenderer;
1507 		layerAttributes.error = tr("unable to create renderer for svg %1").arg(filename);
1508 		newRenderer = NULL;
1509 	}
1510 	//DebugDialog::debug(QString("set up image elapsed (3) %1").arg(t.elapsed()) );
1511 
1512 	if (newRenderer) {
1513 		layerAttributes.setFilename(newRenderer->filename());
1514         if (layerAttributes.createShape) {
1515             createShape(layerAttributes);
1516         }
1517 	}
1518 
1519 	return newRenderer;
1520 }
1521 
updateConnectionsAux(bool includeRatsnest,QList<ConnectorItem * > & already)1522 void ItemBase::updateConnectionsAux(bool includeRatsnest, QList<ConnectorItem *> & already) {
1523 	//DebugDialog::debug("update connections");
1524 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1525 		updateConnections(connectorItem, includeRatsnest, already);
1526 	}
1527 }
1528 
figureHover()1529 void ItemBase::figureHover() {
1530 }
1531 
retrieveSvg(ViewLayer::ViewLayerID viewLayerID,QHash<QString,QString> & svgHash,bool blackOnly,double dpi,double & factor)1532 QString ItemBase::retrieveSvg(ViewLayer::ViewLayerID viewLayerID, QHash<QString, QString> & svgHash, bool blackOnly, double dpi, double & factor)
1533 {
1534 	Q_UNUSED(viewLayerID);
1535 	Q_UNUSED(svgHash);
1536 	Q_UNUSED(blackOnly);
1537 	Q_UNUSED(dpi);
1538     factor = 1;
1539 	return "";
1540 }
1541 
hasConnections()1542 bool ItemBase::hasConnections()
1543 {
1544 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1545 		if (connectorItem->connectionsCount() > 0) return true;
1546 	}
1547 
1548 	return false;
1549 }
1550 
getConnectedColor(ConnectorItem *,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1551 void ItemBase::getConnectedColor(ConnectorItem *, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1552 	brush = ConnectedBrush;
1553 	pen = ConnectedPen;
1554 	opacity = 0.2;
1555 	negativePenWidth = 0;
1556 	negativeOffsetRect = true;
1557 }
1558 
getNormalColor(ConnectorItem *,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1559 void ItemBase::getNormalColor(ConnectorItem *, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1560 	brush = NormalBrush;
1561 	pen = NormalPen;
1562 	opacity = NormalConnectorOpacity;
1563 	negativePenWidth = 0;
1564 	negativeOffsetRect = true;
1565 }
1566 
getUnconnectedColor(ConnectorItem *,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1567 void ItemBase::getUnconnectedColor(ConnectorItem *, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1568 	brush = UnconnectedBrush;
1569 	pen = UnconnectedPen;
1570     opacity = 0.3;
1571 	negativePenWidth = 0;
1572 	negativeOffsetRect = true;
1573 }
1574 
getHoverColor(ConnectorItem *,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1575 void ItemBase::getHoverColor(ConnectorItem *, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1576 	brush = HoverBrush;
1577 	pen = HoverPen;
1578 	opacity = NormalConnectorOpacity;
1579 	negativePenWidth = 0;
1580 	negativeOffsetRect = true;
1581 }
1582 
getEqualPotentialColor(ConnectorItem *,QBrush & brush,QPen & pen,double & opacity,double & negativePenWidth,bool & negativeOffsetRect)1583 void ItemBase::getEqualPotentialColor(ConnectorItem *, QBrush &brush, QPen &pen, double & opacity, double & negativePenWidth, bool & negativeOffsetRect) {
1584 	brush = EqualPotentialBrush;
1585 	pen = EqualPotentialPen;
1586 	opacity = 1.0;
1587 	negativePenWidth = 0;
1588 	negativeOffsetRect = true;
1589 }
1590 
slamZ(double newZ)1591 void ItemBase::slamZ(double newZ) {
1592 	double z = qFloor(m_viewGeometry.z()) + newZ;
1593 	m_viewGeometry.setZ(z);
1594 	setZValue(z);
1595 }
1596 
isEverVisible()1597 bool ItemBase::isEverVisible() {
1598 	return m_everVisible;
1599 }
1600 
setEverVisible(bool v)1601 void ItemBase::setEverVisible(bool v) {
1602 	m_everVisible = v;
1603 }
1604 
connectionIsAllowed(ConnectorItem * other)1605 bool ItemBase::connectionIsAllowed(ConnectorItem * other) {
1606 	return ViewLayer::canConnect(this->viewLayerID(), other->attachedToViewLayerID());
1607 }
1608 
getProperty(const QString & key)1609 QString ItemBase::getProperty(const QString & key) {
1610 	if (m_modelPart == NULL) return "";
1611 
1612     QString result = m_modelPart->localProp(key).toString();
1613 	if (!result.isEmpty()) return result;
1614 
1615 	return m_modelPart->properties().value(key, "");
1616 }
1617 
rightClickedConnector()1618 ConnectorItem * ItemBase::rightClickedConnector() {
1619 	return m_rightClickedConnector;
1620 }
1621 
connectedColor()1622 QColor ItemBase::connectedColor() {
1623 	return ConnectedPen.color();
1624 }
1625 
unconnectedColor()1626 QColor ItemBase::unconnectedColor() {
1627 	return UnconnectedPen.color();
1628 }
1629 
standardConnectedColor()1630 QColor ItemBase::standardConnectedColor() {
1631 	return StandardConnectedColor;
1632 }
1633 
standardUnconnectedColor()1634 QColor ItemBase::standardUnconnectedColor() {
1635 	return StandardUnconnectedColor;
1636 }
1637 
setConnectedColor(QColor & c)1638 void ItemBase::setConnectedColor(QColor & c) {
1639 	ConnectedPen.setColor(c);
1640 	ConnectedBrush.setColor(c);
1641 }
1642 
setUnconnectedColor(QColor & c)1643 void ItemBase::setUnconnectedColor(QColor & c) {
1644 	UnconnectedPen.setColor(c);
1645 	UnconnectedBrush.setColor(c);
1646 }
1647 
translatePropertyName(const QString & key)1648 QString ItemBase::translatePropertyName(const QString & key) {
1649 	return TranslatedPropertyNames.value(key.toLower(), key);
1650 }
1651 
canEditPart()1652 bool ItemBase::canEditPart() {
1653 	return false;
1654 }
1655 
hasCustomSVG()1656 bool ItemBase::hasCustomSVG() {
1657 	return false;
1658 }
1659 
setProp(const QString & prop,const QString & value)1660 void ItemBase::setProp(const QString & prop, const QString & value) {
1661 	if (!m_modelPart) return;
1662 
1663     //DebugDialog::debug(QString("setting prop %1 %2").arg(prop).arg(value));
1664 	m_modelPart->setLocalProp(prop, value);
1665 }
1666 
prop(const QString & p)1667 QString ItemBase::prop(const QString & p)
1668 {
1669 	if (m_modelPart == NULL) return "";
1670 
1671 	return m_modelPart->localProp(p).toString();
1672 }
1673 
isObsolete()1674 bool ItemBase::isObsolete() {
1675 	if (modelPart() == NULL) return false;
1676 
1677 	return modelPart()->isObsolete();
1678 }
1679 
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)1680 bool ItemBase::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
1681 {
1682     Q_UNUSED(hide);                 // assume this is set by the caller (HtmlInfoView)
1683 	returnWidget = NULL;
1684 	returnProp = ItemBase::translatePropertyName(prop);
1685 	returnValue = value;
1686 
1687 	if (prop.compare("family", Qt::CaseInsensitive) == 0) {
1688 		return true;
1689 	}
1690 	if (prop.compare("id", Qt::CaseInsensitive) == 0) {
1691 		return true;
1692 	}
1693 #ifndef QT_NO_DEBUG
1694     if (prop.compare("svg", Qt::CaseInsensitive) == 0 || prop.compare("fzp" , Qt::CaseInsensitive) == 0) {
1695         QFileInfo fileInfo(value);
1696         if (fileInfo.exists()) {
1697             ClickableLabel * label = new ClickableLabel(fileInfo.fileName(), parent);
1698             label->setProperty("path", value);
1699             label->setToolTip(value);
1700             connect(label, SIGNAL(clicked()), this, SLOT(showInFolder()));
1701             returnWidget = label;
1702         }
1703         return true;
1704     }
1705 #endif
1706 
1707 	QString tempValue = value;
1708 	QStringList values = collectValues(family, prop, tempValue);
1709 	if (values.count() > 1) {
1710 		FamilyPropertyComboBox * comboBox = new FamilyPropertyComboBox(family, prop, parent);
1711 		comboBox->setObjectName("infoViewComboBox");
1712 
1713 		comboBox->addItems(values);
1714 		comboBox->setCurrentIndex(comboBox->findText(tempValue));
1715 		comboBox->setEnabled(swappingEnabled);
1716         comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
1717 		connect(comboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(swapEntry(const QString &)));
1718 
1719 		returnWidget = comboBox;
1720 		m_propsMap.insert(prop, tempValue);
1721 		return true;
1722 	}
1723 
1724 	return true;
1725 }
1726 
swapEntry(const QString & text)1727 void ItemBase::swapEntry(const QString & text) {
1728     FamilyPropertyComboBox * comboBox = qobject_cast<FamilyPropertyComboBox *>(sender());
1729     if (comboBox == NULL) return;
1730 
1731     m_propsMap.insert(comboBox->prop(), text);
1732 
1733     InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
1734     if (infoGraphicsView != NULL) {
1735         infoGraphicsView->swap(comboBox->family(), comboBox->prop(), m_propsMap, this);
1736     }
1737 }
1738 
setReferenceModel(ReferenceModel * rm)1739 void ItemBase::setReferenceModel(ReferenceModel * rm) {
1740 	TheReferenceModel = rm;
1741 }
1742 
collectValues(const QString & family,const QString & prop,QString & value)1743 QStringList ItemBase::collectValues(const QString & family, const QString & prop, QString & value) {
1744 	Q_UNUSED(value);
1745 
1746 	if (TheReferenceModel == NULL) return ___emptyStringList___;
1747 
1748 	QStringList values = CachedValues.value(family + prop, QStringList());
1749 	if (values.count() > 0) return values;
1750 
1751 	values = TheReferenceModel->propValues(family, prop, true);
1752 
1753 	// sort values numerically
1754 	NumberMatcherValues.clear();
1755 	bool ok = true;
1756 	foreach(QString opt, values) {
1757 		int ix = NumberMatcher.indexIn(opt);
1758 		if (ix < 0) {
1759 			ok = false;
1760 			break;
1761 		}
1762 
1763 		double n = TextUtils::convertFromPowerPrefix(NumberMatcher.cap(1) + NumberMatcher.cap(5), "");
1764 		NumberMatcherValues.insert(opt, n);
1765 	}
1766 	if (ok) {
1767 		qSort(values.begin(), values.end(), numberValueLessThan);
1768 	}
1769 
1770 	CachedValues.insert(family + prop, values);
1771     //debugInfo("cached " + prop);
1772     //foreach(QString v, values) {
1773     //    DebugDialog::debug("\t" + v);
1774     //}
1775 	return values;
1776 }
1777 
resetValues(const QString & family,const QString & prop)1778 void ItemBase::resetValues(const QString & family, const QString & prop) {
1779 	CachedValues.remove(family + prop);
1780 }
1781 
hasPartLabel()1782 bool ItemBase::hasPartLabel() {
1783 	return true;
1784 }
1785 
filename()1786 const QString & ItemBase::filename() {
1787 	return m_filename;
1788 }
1789 
setFilename(const QString & fn)1790 void ItemBase::setFilename(const QString & fn) {
1791 	m_filename = fn;
1792 }
1793 
isPlural()1794 ItemBase::PluralType ItemBase::isPlural() {
1795 	return ItemBase::NotSure;
1796 }
1797 
viewLayerPlacement() const1798 ViewLayer::ViewLayerPlacement ItemBase::viewLayerPlacement() const {
1799 	return m_viewLayerPlacement;
1800 }
1801 
setViewLayerPlacement(ViewLayer::ViewLayerPlacement viewLayerPlacement)1802 void ItemBase::setViewLayerPlacement(ViewLayer::ViewLayerPlacement viewLayerPlacement) {
1803 	m_viewLayerPlacement = viewLayerPlacement;
1804 }
1805 
partLabelViewLayerID()1806 ViewLayer::ViewLayerID ItemBase::partLabelViewLayerID() {
1807 	if (m_partLabel == NULL) return ViewLayer::UnknownLayer;
1808 	if (!m_partLabel->initialized()) return ViewLayer::UnknownLayer;
1809 	return m_partLabel->viewLayerID();
1810 }
1811 
makePartLabelSvg(bool blackOnly,double dpi,double printerScale)1812 QString ItemBase::makePartLabelSvg(bool blackOnly, double dpi, double printerScale) {
1813 	if (m_partLabel == NULL) return "";
1814 	if (!m_partLabel->initialized()) return "";
1815 	return m_partLabel->makeSvg(blackOnly, dpi, printerScale, true);
1816 }
1817 
partLabelScenePos()1818 QPointF ItemBase::partLabelScenePos() {
1819 	if (m_partLabel == NULL) return QPointF();
1820 	if (!m_partLabel->initialized()) return QPointF();
1821 	return m_partLabel->scenePos();
1822 }
1823 
partLabelSceneBoundingRect()1824 QRectF ItemBase::partLabelSceneBoundingRect() {
1825 	if (m_partLabel == NULL) return QRectF();
1826 	if (!m_partLabel->initialized()) return QRectF();
1827 	return m_partLabel->sceneBoundingRect();
1828 }
1829 
getFlipDoc(ModelPart * modelPart,const QString & filename,ViewLayer::ViewLayerID viewLayerID,ViewLayer::ViewLayerPlacement viewLayerPlacement,QDomDocument & flipDoc,Qt::Orientations orientation)1830 bool ItemBase::getFlipDoc(ModelPart * modelPart, const QString & filename, ViewLayer::ViewLayerID viewLayerID, ViewLayer::ViewLayerPlacement viewLayerPlacement, QDomDocument & flipDoc, Qt::Orientations orientation)
1831 {
1832     if (!modelPart->flippedSMD()) {
1833         // add copper1 layer to THT if it is missing
1834         fixCopper1(modelPart, filename, viewLayerID, viewLayerPlacement, flipDoc);
1835     }
1836 
1837 	if (viewLayerPlacement == ViewLayer::NewBottom) {
1838         if (modelPart->flippedSMD()) {
1839 		    if (viewLayerID == ViewLayer::Copper0) {
1840 			    SvgFlattener::flipSMDSvg(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper1), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper0), GraphicsUtils::SVGDPI, orientation);
1841 			    return true;
1842 		    }
1843 		    else if (viewLayerID == ViewLayer::Silkscreen0) {
1844 			    SvgFlattener::flipSMDSvg(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Silkscreen1), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Silkscreen0), GraphicsUtils::SVGDPI, orientation);
1845 			    return true;
1846 		    }
1847             return false;
1848         }
1849 
1850         if (modelPart->itemType() == ModelPart::Part) {
1851 		    if (viewLayerID == ViewLayer::Copper0) {
1852                 SvgFlattener::replaceElementID(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper0), "");
1853 			    //QString t1 = flipDoc.toString();
1854                 SvgFlattener::flipSMDSvg(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper1), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper0), GraphicsUtils::SVGDPI, orientation);
1855 			    //QString t2 = flipDoc.toString();
1856 			    return true;
1857 		    }
1858 		    if (viewLayerID == ViewLayer::Copper1) {
1859 			    SvgFlattener::replaceElementID(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper1), "");
1860 			    //QString t1 = flipDoc.toString();
1861 			    SvgFlattener::flipSMDSvg(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper0), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper1), GraphicsUtils::SVGDPI, orientation);
1862 			    //QString t2 = flipDoc.toString();
1863 			    return true;
1864 		    }
1865 		    else if (viewLayerID == ViewLayer::Silkscreen0) {
1866 			    SvgFlattener::flipSMDSvg(filename, "", flipDoc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Silkscreen1), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Silkscreen0), GraphicsUtils::SVGDPI, orientation);
1867 			    return true;
1868 		    }
1869         }
1870 	}
1871 
1872 	return false;
1873 }
1874 
fixCopper1(ModelPart * modelPart,const QString & filename,ViewLayer::ViewLayerID viewLayerID,ViewLayer::ViewLayerPlacement viewLayerPlacement,QDomDocument & doc)1875 bool ItemBase::fixCopper1(ModelPart * modelPart, const QString & filename, ViewLayer::ViewLayerID viewLayerID, ViewLayer::ViewLayerPlacement viewLayerPlacement, QDomDocument & doc)
1876 {
1877 	Q_UNUSED(viewLayerPlacement);
1878 	if (viewLayerID != ViewLayer::Copper1) return false;
1879 	if (!modelPart->needsCopper1()) return false;
1880 
1881 	return TextUtils::addCopper1(filename, doc, ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper0), ViewLayer::viewLayerXmlNameFromID(ViewLayer::Copper1));
1882 }
1883 
calcRotation(QTransform & rotation,QPointF center,ViewGeometry & vg2)1884 void ItemBase::calcRotation(QTransform & rotation, QPointF center, ViewGeometry & vg2)
1885 {
1886 	vg2.setLoc(GraphicsUtils::calcRotation(rotation, center, pos(), boundingRectWithoutLegs().center()));
1887 }
1888 
updateConnectors()1889 void ItemBase::updateConnectors()
1890 {
1891 	if (!isEverVisible()) return;
1892 
1893     QList<ConnectorItem *> visited;
1894 	foreach(ConnectorItem * connectorItem, cachedConnectorItems()) {
1895 		connectorItem->restoreColor(visited);
1896 	}
1897 	//DebugDialog::debug(QString("set up connectors restore:%1").arg(count));
1898 }
1899 
moduleID()1900 const QString & ItemBase::moduleID() {
1901 	if (m_modelPart) return m_modelPart->moduleID();
1902 
1903 	return ___emptyString___;
1904 }
1905 
moveLock()1906 bool ItemBase::moveLock() {
1907 	return m_moveLock;
1908 }
1909 
setMoveLock(bool moveLock)1910 void ItemBase::setMoveLock(bool moveLock)
1911 {
1912 	m_moveLock = moveLock;
1913 	if (moveLock) {
1914         if (m_moveLockItem == NULL) {
1915 		    if (!MoveLockRenderer.isValid()) {
1916 			    QString fn(":resources/images/part_lock.svg");
1917 			    bool success = MoveLockRenderer.load(fn);
1918 			    DebugDialog::debug(QString("movelock load success %1").arg(success));
1919 		    }
1920 
1921 		    m_moveLockItem = new QGraphicsSvgItem();
1922 		    m_moveLockItem->setAcceptHoverEvents(false);
1923 		    m_moveLockItem->setAcceptedMouseButtons(Qt::NoButton);
1924 		    m_moveLockItem->setSharedRenderer(&MoveLockRenderer);
1925 		    m_moveLockItem->setPos(0,0);
1926 		    m_moveLockItem->setZValue(-99999);
1927 		    m_moveLockItem->setParentItem(this);
1928 		    m_moveLockItem->setVisible(true);
1929         }
1930 
1931 	}
1932 	else {
1933 		if (m_moveLockItem) {
1934 			delete m_moveLockItem;
1935 			m_moveLockItem = NULL;
1936 		}
1937 	}
1938 
1939     if (m_stickyItem) {
1940 		m_stickyItem->setPos(m_moveLockItem == NULL ? 0 : m_moveLockItem->boundingRect().width() + 1, 0);
1941     }
1942 
1943 	update();
1944 }
1945 
debugInfo(const QString & msg) const1946 void ItemBase::debugInfo(const QString & msg) const
1947 {
1948 
1949 #ifndef QT_NO_DEBUG
1950     debugInfo2(msg);
1951 #else
1952 	Q_UNUSED(msg);
1953 #endif
1954 }
1955 
debugInfo2(const QString & msg) const1956 void ItemBase::debugInfo2(const QString & msg) const
1957 {
1958 	DebugDialog::debug(QString("%1 ti:'%2' id:%3 it:'%4' vid:%9 vlid:%5 spec:%6 x:%11 y:%12 z:%10 flg:%7 gi:%8")
1959 		.arg(msg)
1960         .arg(this->constTitle())
1961 		.arg(this->id())
1962 		.arg(this->instanceTitle())
1963 		.arg(this->viewLayerID())
1964 		.arg(this->viewLayerPlacement())
1965 		.arg(this->wireFlags())
1966 		.arg((long) dynamic_cast<const QGraphicsItem *const>(this), 0, 16)
1967 		.arg(m_viewID)
1968         .arg(this->zValue())
1969         .arg(this->pos().x())
1970         .arg(this->pos().y())
1971 	);
1972 
1973 	/*
1974 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
1975 		if (connectorItem) connectorItem->debugInfo("\t");
1976 	}
1977 	*/
1978 }
1979 
addedToScene(bool temporary)1980 void ItemBase::addedToScene(bool temporary) {
1981 	if (this->scene() && instanceTitle().isEmpty() && !temporary) {
1982 		setTooltip();
1983         if (isBaseSticky() && isLocalSticky()) {
1984             // ensure icon is visible
1985             setLocalSticky(true);
1986         }
1987 	}
1988 }
1989 
hasPartNumberProperty()1990 bool ItemBase::hasPartNumberProperty()
1991 {
1992 	return true;
1993 }
1994 
collectPropsMap(QString & family,QMap<QString,QString> & propsMap)1995 void ItemBase::collectPropsMap(QString & family, QMap<QString, QString> & propsMap) {
1996 	QHash<QString, QString> properties;
1997 	properties = m_modelPart->properties();
1998 	family = properties.value("family", "");
1999 	foreach (QString key, properties.keys()) {
2000 		if (key.compare("family") == 0) continue;
2001 		if (key.compare("id") == 0) continue;
2002 
2003 		QString value = properties.value(key,"");
2004 		QString tempValue = value;
2005 		QStringList values = collectValues(family, key, tempValue);
2006 		propsMap.insert(key, tempValue);
2007 		DebugDialog::debug(QString("props map %1 %2").arg(key).arg(tempValue));
2008 	}
2009 }
2010 
setDropOffset(QPointF)2011 void ItemBase::setDropOffset(QPointF)
2012 {
2013 }
2014 
hasRubberBandLeg() const2015 bool ItemBase::hasRubberBandLeg() const
2016 {
2017 	return m_hasRubberBandLeg;
2018 }
2019 
sceneEvent(QEvent * event)2020 bool ItemBase::sceneEvent(QEvent *event)
2021 {
2022 	return QGraphicsSvgItem::sceneEvent(event);
2023 }
2024 
cachedConnectorItems()2025 const QList<ConnectorItem *> & ItemBase::cachedConnectorItems()
2026 {
2027 	if (m_cachedConnectorItems.isEmpty()) {
2028 		foreach (QGraphicsItem * childItem, childItems()) {
2029 			ConnectorItem * connectorItem = dynamic_cast<ConnectorItem *>(childItem);
2030 			if (connectorItem != NULL) m_cachedConnectorItems.append(connectorItem);
2031 		}
2032 	}
2033 
2034 	return m_cachedConnectorItems;
2035 }
2036 
cachedConnectorItemsConst() const2037 const QList<ConnectorItem *> & ItemBase::cachedConnectorItemsConst() const
2038 {
2039 	return m_cachedConnectorItems;
2040 }
2041 
clearConnectorItemCache()2042 void ItemBase::clearConnectorItemCache()
2043 {
2044 	m_cachedConnectorItems.clear();
2045 }
2046 
killRubberBandLeg()2047 void ItemBase::killRubberBandLeg() {
2048 	if (!hasRubberBandLeg()) return;
2049 
2050 	prepareGeometryChange();
2051 
2052 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
2053 		connectorItem->killRubberBandLeg();
2054 	}
2055 }
2056 
wireFlags() const2057 ViewGeometry::WireFlags ItemBase::wireFlags() const {
2058 	return m_viewGeometry.wireFlags();
2059 }
2060 
boundingRectWithoutLegs() const2061 QRectF ItemBase::boundingRectWithoutLegs() const
2062 {
2063 	return boundingRect();
2064 }
2065 
boundingRect() const2066 QRectF ItemBase::boundingRect() const
2067 {
2068 	FSvgRenderer * frenderer = fsvgRenderer();
2069 	if (frenderer == NULL) {
2070 		return QGraphicsSvgItem::boundingRect();
2071 	}
2072 
2073 	QSizeF s = frenderer->defaultSizeF();
2074 	QRectF r(0,0, s.width(), s.height());
2075 	return r;
2076 }
2077 
hoverShape() const2078 QPainterPath ItemBase::hoverShape() const
2079 {
2080 	return shape();
2081 }
2082 
getCursor(Qt::KeyboardModifiers)2083 const QCursor * ItemBase::getCursor(Qt::KeyboardModifiers)
2084 {
2085 	return CursorMaster::MoveCursor;
2086 }
2087 
partLabel()2088 PartLabel * ItemBase::partLabel() {
2089 	return m_partLabel;
2090 }
2091 
doneLoading()2092 void ItemBase::doneLoading() {
2093 }
2094 
family()2095 QString ItemBase::family() {
2096 	return modelPart()->family();
2097 }
2098 
getPixmap(QSize size)2099 QPixmap * ItemBase::getPixmap(QSize size) {
2100     return FSvgRenderer::getPixmap(renderer(), size);
2101 }
2102 
fsvgRenderer() const2103 FSvgRenderer * ItemBase::fsvgRenderer() const {
2104     if (m_fsvgRenderer) return m_fsvgRenderer;
2105 
2106     FSvgRenderer * f = qobject_cast<FSvgRenderer *>(renderer());
2107     if (f == NULL) {
2108         DebugDialog::debug("shouldn't happen: missing fsvgRenderer");
2109     }
2110     return f;
2111 }
2112 
setSharedRendererEx(FSvgRenderer * newRenderer)2113 void ItemBase::setSharedRendererEx(FSvgRenderer * newRenderer) {
2114 	if (newRenderer != m_fsvgRenderer) {
2115 		setSharedRenderer(newRenderer);  // original renderer is deleted if it is not shared
2116         if (m_fsvgRenderer) delete m_fsvgRenderer;
2117         m_fsvgRenderer = newRenderer;
2118 	}
2119 	else {
2120 		update();
2121 	}
2122 	m_size = newRenderer->defaultSizeF();
2123     //debugInfo(QString("set size %1, %2").arg(m_size.width()).arg(m_size.height()));
2124 }
2125 
reloadRenderer(const QString & svg,bool fastLoad)2126 bool ItemBase::reloadRenderer(const QString & svg, bool fastLoad) {
2127 	if (!svg.isEmpty()) {
2128 		//DebugDialog::debug(svg);
2129 		prepareGeometryChange();
2130 		bool result = fastLoad ? fsvgRenderer()->fastLoad(svg.toUtf8()) : fsvgRenderer()->loadSvgString(svg.toUtf8());
2131 		if (result) {
2132             update();
2133 		}
2134 
2135 		return result;
2136 	}
2137 
2138 	return false;
2139 }
2140 
resetRenderer(const QString & svg)2141 bool ItemBase::resetRenderer(const QString & svg) {
2142     // use resetRenderer instead of reloadRender because if the svg size changes, with reloadRenderer the new image seems to be scaled to the old bounds
2143     // what I don't understand is why the old renderer causes a crash if it is deleted here
2144 
2145     QString nothing;
2146     return resetRenderer(svg, nothing);
2147 }
2148 
resetRenderer(const QString & svg,QString & newSvg)2149 bool ItemBase::resetRenderer(const QString & svg, QString & newSvg) {
2150     // use resetRenderer instead of reloadRender because if the svg size changes, with reloadRenderer the new image seems to be scaled to the old bounds
2151     // what I don't understand is why the old renderer causes a crash if it is deleted here
2152 
2153     FSvgRenderer * newRenderer = new FSvgRenderer();
2154     bool result = newRenderer->loadSvgString(svg, newSvg);
2155     if (result) {
2156         //DebugDialog::debug("reloaded");
2157         //DebugDialog::debug(newSvg);
2158         setSharedRendererEx(newRenderer);
2159     }
2160     else {
2161         delete newRenderer;
2162     }
2163     return result;
2164 }
2165 
getPixmaps(QPixmap * & pixmap1,QPixmap * & pixmap2,QPixmap * & pixmap3,bool swappingEnabled,QSize size)2166 void ItemBase::getPixmaps(QPixmap * & pixmap1, QPixmap * & pixmap2, QPixmap * & pixmap3, bool swappingEnabled, QSize size)
2167 {
2168     pixmap1 = getPixmap(ViewLayer::BreadboardView, swappingEnabled, size);
2169     pixmap2 = getPixmap(ViewLayer::SchematicView, swappingEnabled, size);
2170     pixmap3 = getPixmap(ViewLayer::PCBView, swappingEnabled, size);
2171 }
2172 
getPixmap(ViewLayer::ViewID vid,bool swappingEnabled,QSize size)2173 QPixmap * ItemBase::getPixmap(ViewLayer::ViewID vid, bool swappingEnabled, QSize size)
2174 {
2175     ItemBase * vItemBase = NULL;
2176 
2177     if (viewID() == vid) {
2178         if (!isEverVisible()) return NULL;
2179     }
2180     else {
2181         vItemBase = modelPart()->viewItem(vid);
2182         if (vItemBase && !vItemBase->isEverVisible()) return NULL;
2183     }
2184 
2185     vid = useViewIDForPixmap(vid, swappingEnabled);
2186     if (vid == ViewLayer::UnknownView) return NULL;
2187 
2188     if (viewID() == vid) {
2189         return getPixmap(size);
2190     }
2191 
2192     if (vItemBase) {
2193         return vItemBase->getPixmap(size);
2194     }
2195 
2196 
2197 	if (!modelPart()->hasViewFor(vid)) return NULL;
2198 
2199 	QString baseName = modelPart()->hasBaseNameFor(vid);
2200 	if (baseName.isEmpty()) return NULL;
2201 
2202 	QString filename = PartFactory::getSvgFilename(modelPart(), baseName, true, true);
2203 	if (filename.isEmpty()) {
2204 		return NULL;
2205 	}
2206 
2207 	QSvgRenderer renderer(filename);
2208 
2209 	QPixmap * pixmap = new QPixmap(size);
2210 	pixmap->fill(Qt::transparent);
2211 	QPainter painter(pixmap);
2212 	// preserve aspect ratio
2213 	QSize def = renderer.defaultSize();
2214 	double newW = size.width();
2215 	double newH = newW * def.height() / def.width();
2216 	if (newH > size.height()) {
2217 		newH = size.height();
2218 		newW = newH * def.width() / def.height();
2219 	}
2220 	QRectF bounds((size.width() - newW) / 2.0, (size.height() - newH) / 2.0, newW, newH);
2221 	renderer.render(&painter, bounds);
2222 	painter.end();
2223 
2224 	return pixmap;
2225 }
2226 
useViewIDForPixmap(ViewLayer::ViewID vid,bool)2227 ViewLayer::ViewID ItemBase::useViewIDForPixmap(ViewLayer::ViewID vid, bool)
2228 {
2229     if (vid == ViewLayer::BreadboardView) {
2230         return ViewLayer::IconView;
2231     }
2232 
2233     return vid;
2234 }
2235 
makeLocalModifications(QByteArray &,const QString &)2236 bool ItemBase::makeLocalModifications(QByteArray &, const QString & ) {
2237     // a bottleneck for modifying part svg xml at setupImage time
2238     return false;
2239 }
2240 
showConnectors(const QStringList & connectorIDs)2241 void ItemBase::showConnectors(const QStringList & connectorIDs) {
2242 	foreach (ConnectorItem * connectorItem, cachedConnectorItems()) {
2243 		if (connectorIDs.contains(connectorItem->connectorSharedID())) {
2244 			connectorItem->setVisible(true);
2245 		}
2246 	}
2247 }
2248 
setItemIsSelectable(bool selectable)2249 void ItemBase::setItemIsSelectable(bool selectable) {
2250 	setFlag(QGraphicsItem::ItemIsSelectable, selectable);
2251 }
2252 
inRotation()2253 bool ItemBase::inRotation() {
2254 	return m_inRotation;
2255 }
2256 
setInRotation(bool val)2257 void ItemBase::setInRotation(bool val) {
2258 	m_inRotation = val;
2259 }
2260 
addSubpart(ItemBase * sub)2261 void ItemBase::addSubpart(ItemBase * sub)
2262 {
2263     this->debugInfo("super");
2264     sub->debugInfo("\t");
2265     m_subparts.append(sub);
2266     sub->setSuperpart(this);
2267     foreach (ConnectorItem * connectorItem, sub->cachedConnectorItems()) {
2268         Bus * subbus = connectorItem->bus();
2269         Connector * subconnector = NULL;
2270         if (subbus == NULL) {
2271             subconnector = connectorItem->connector();
2272             if (subconnector) {
2273                 subbus = new Bus(NULL, NULL);
2274                 subconnector->setBus(subbus);
2275             }
2276         }
2277 
2278         Connector * connector = modelPart()->getConnector(connectorItem->connectorSharedID());
2279         if (connector) {
2280             if (subbus) subbus->addSubConnector(connector);
2281             if (subconnector) {
2282                 Bus * bus = connector->bus();
2283                 if (bus == NULL) {
2284                     bus = new Bus(NULL, NULL);
2285                     connector->setBus(bus);
2286                 }
2287 
2288                 bus->addSubConnector(subconnector);
2289             }
2290         }
2291     }
2292 }
2293 
setSuperpart(ItemBase * super)2294 void ItemBase::setSuperpart(ItemBase * super) {
2295     m_superpart = super;
2296 }
2297 
superpart()2298 ItemBase * ItemBase::superpart() {
2299     return m_superpart;
2300 }
2301 
findSubpart(const QString & connectorID,ViewLayer::ViewLayerPlacement spec)2302 ItemBase * ItemBase::findSubpart(const QString & connectorID, ViewLayer::ViewLayerPlacement spec) {
2303     foreach (ItemBase * itemBase, m_subparts) {
2304         ConnectorItem * connectorItem = itemBase->findConnectorItemWithSharedID(connectorID, spec);
2305         if (connectorItem) return itemBase;
2306     }
2307 
2308     return NULL;
2309 }
2310 
subparts()2311 const QList< QPointer<ItemBase> > & ItemBase::subparts()
2312 {
2313     return m_subparts;
2314 }
2315 
prepareProps(ModelPart * modelPart,bool wantDebug,QStringList & keys)2316 QHash<QString, QString> ItemBase::prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys)
2317 {
2318     m_propsMap.clear();
2319 
2320     // TODO: someday get local props
2321 	QHash<QString, QString> props = modelPart->properties();
2322 	QString family = props.value("family", "").toLower();
2323 
2324     // ensure family is first;
2325 	keys = props.keys();
2326 	keys.removeOne("family");
2327 	keys.push_front("family");
2328 
2329 	// ensure part number  is last
2330 	QString partNumber = props.value(ModelPartShared::PartNumberPropertyName, "").toLower();
2331 	keys.removeOne(ModelPartShared::PartNumberPropertyName);
2332 
2333 	if (wantDebug) {
2334 		props.insert("id", QString("%1 %2 %3")
2335 			.arg(QString::number(id()))
2336 			.arg(modelPart->moduleID())
2337 			.arg(ViewLayer::viewLayerNameFromID(viewLayerID()))
2338 		);
2339 		keys.insert(1, "id");
2340 
2341 		int insertAt = 2;
2342 		PaletteItemBase * paletteItemBase = qobject_cast<PaletteItemBase *>(this);
2343 		if (paletteItemBase != NULL) {
2344 			props.insert("svg", paletteItemBase->filename());
2345 			keys.insert(insertAt++, "svg");
2346 		}
2347 		props.insert("class", this->metaObject()->className());
2348 		keys.insert(insertAt++, "class");
2349 
2350         if (modelPart->modelPartShared()) {
2351 			props.insert("fzp",  modelPart->path());
2352 			keys.insert(insertAt++, "fzp");
2353 		}
2354 	}
2355 
2356 	// ensure part number is last
2357 	if (hasPartNumberProperty()) {
2358 		keys.append(ModelPartShared::PartNumberPropertyName);
2359 	}
2360 
2361     return props;
2362 }
2363 
setSquashShape(bool squashShape)2364 void ItemBase::setSquashShape(bool squashShape) {
2365     m_squashShape = squashShape;
2366 }
2367 
createShape(LayerAttributes & layerAttributes)2368 void ItemBase::createShape(LayerAttributes & layerAttributes) {
2369     switch (layerAttributes.viewID) {
2370         case ViewLayer::SchematicView:
2371         case ViewLayer::PCBView:
2372             break;
2373         default:
2374             return;
2375     }
2376 
2377     if (!isEverVisible()) return;
2378 
2379 	QString errorStr;
2380 	int errorLine;
2381 	int errorColumn;
2382     QDomDocument doc;
2383 	if (!doc.setContent(layerAttributes.loaded(), &errorStr, &errorLine, &errorColumn)) {
2384 		return;
2385 	}
2386 
2387     QDomElement root = doc.documentElement();
2388 
2389     QRectF viewBox;
2390     double w, h;
2391     TextUtils::ensureViewBox(doc, 1, viewBox, true, w, h, true);
2392     double svgDPI = viewBox.width() / w;
2393     int selectionExtra = layerAttributes.viewID == ViewLayer::SchematicView ? 20 : 10;
2394     SvgFileSplitter::forceStrokeWidth(root, svgDPI * selectionExtra / GraphicsUtils::SVGDPI, "#000000", true, false);
2395 
2396     double imageDPI = GraphicsUtils::SVGDPI;
2397     QRectF sourceRes(0, 0, w * imageDPI, h * imageDPI);
2398     QSize imgSize(qCeil(sourceRes.width()), qCeil(sourceRes.height()));
2399     QImage image(imgSize, QImage::Format_Mono);
2400     image.fill(0xffffffff);
2401     renderOne(&doc, &image, sourceRes);
2402     QBitmap bitmap = QBitmap::fromImage(image);
2403     QRegion region(bitmap);
2404     m_selectionShape.addRegion(region);
2405 
2406 #ifndef QT_NODEBUG
2407     //QFileInfo info(layerAttributes.filename());
2408     //bitmap.save(FolderUtils::getUserDataStorePath("") + "/bitmap." + info.completeBaseName() + "." + QString::number(layerAttributes.viewLayerID) + ".png");
2409     //image.save(FolderUtils::getUserDataStorePath("") + "/image." + info.completeBaseName() + "." + QString::number(layerAttributes.viewLayerID) + ".png");
2410 #endif
2411 }
2412 
selectionShape()2413 const QPainterPath & ItemBase::selectionShape() {
2414     return m_selectionShape;
2415 }
2416 
setTransform2(const QTransform & transform)2417 void ItemBase::setTransform2(const QTransform & transform)
2418 {
2419     setTransform(transform);
2420 }
2421 
renderOne(QDomDocument * masterDoc,QImage * image,const QRectF & renderRect)2422 void ItemBase::renderOne(QDomDocument * masterDoc, QImage * image, const QRectF & renderRect) {
2423     QByteArray byteArray = masterDoc->toByteArray();
2424 	QSvgRenderer renderer(byteArray);
2425 	QPainter painter;
2426 	painter.begin(image);
2427 	painter.setRenderHint(QPainter::Antialiasing, false);
2428     painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
2429 	renderer.render(&painter, renderRect);
2430 	painter.end();
2431 }
2432 
2433 
initLayerAttributes(LayerAttributes & layerAttributes,ViewLayer::ViewID viewID,ViewLayer::ViewLayerID viewLayerID,ViewLayer::ViewLayerPlacement viewLayerPlacement,bool doConnectors,bool doCreateShape)2434 void ItemBase::initLayerAttributes(LayerAttributes & layerAttributes, ViewLayer::ViewID viewID, ViewLayer::ViewLayerID viewLayerID, ViewLayer::ViewLayerPlacement viewLayerPlacement, bool doConnectors, bool doCreateShape) {
2435     layerAttributes.viewID = viewID;
2436     layerAttributes.viewLayerID = viewLayerID;
2437     layerAttributes.viewLayerPlacement = viewLayerPlacement;
2438     layerAttributes.doConnectors = doConnectors;
2439     layerAttributes.createShape = doCreateShape;
2440     InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
2441 	if (infoGraphicsView != NULL) {
2442 		layerAttributes.orientation = infoGraphicsView->smdOrientation();
2443 	}
2444 }
2445 
showInFolder()2446 void ItemBase::showInFolder() {
2447     QString path = sender()->property("path").toString();
2448     if (!path.isEmpty()) {
2449         FolderUtils::showInFolder(path);
2450         QClipboard *clipboard = QApplication::clipboard();
2451 	    if (clipboard != NULL) {
2452 		    clipboard->setText(path);
2453 	    }
2454     }
2455 }
2456 
getInspectorTitle()2457 QString ItemBase::getInspectorTitle() {
2458     QString t = instanceTitle();
2459     if (!t.isEmpty()) return t;
2460 
2461     return title();
2462 }
2463 
setInspectorTitle(const QString & oldText,const QString & newText)2464 void ItemBase::setInspectorTitle(const QString & oldText, const QString & newText) {
2465     InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
2466     if (infoGraphicsView == NULL) return;
2467 
2468 	DebugDialog::debug(QString("set instance title to %1").arg(newText));
2469 	infoGraphicsView->setInstanceTitle(id(), oldText, newText, true, false);
2470 }
2471