1 /*******************************************************************
2 
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5 
6 Fritzing is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 Fritzing is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
18 
19 ********************************************************************
20 
21 $Revision: 6956 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-07 12:14:50 +0200 (So, 07. Apr 2013) $
24 
25 ********************************************************************/
26 
27 #include "modelpart.h"
28 #include "../debugdialog.h"
29 #include "../connectors/connectorshared.h"
30 #include "../connectors/busshared.h"
31 #include "../connectors/bus.h"
32 #include "../version/version.h"
33 #include "../utils/folderutils.h"
34 #include "../utils/textutils.h"
35 #include "../items/itembase.h"
36 #include "../items/partfactory.h"
37 
38 #include <QDomElement>
39 #include <QBitArray>
40 
41 long ModelPart::m_nextIndex = 0;
42 const int ModelPart::indexMultiplier = 10;
43 QStringList ModelPart::m_possibleFolders;
44 
45 typedef QHash<QString, ModelPartList*> InstanceTitleIncrementHash;
46 static QHash<QObject *, InstanceTitleIncrementHash *> AllInstanceTitleIncrements;
47 InstanceTitleIncrementHash NullInstanceTitleIncrements;
48 
49 static const QRegExp InstanceTitleRegExp("^(.*[^\\d])(\\d+)$");
50 
51 static const QList<ViewImage *> EmptyViewImages;
52 
53 ////////////////////////////////////////
54 
ModelPart(ItemType type)55 ModelPart::ModelPart(ItemType type)
56 	: QObject()
57 {
58 	commonInit(type);
59 	m_modelPartShared = NULL;
60 	m_index = m_nextIndex++;
61 }
62 
ModelPart(QDomDocument & domDocument,const QString & path,ItemType type)63 ModelPart::ModelPart(QDomDocument & domDocument, const QString & path, ItemType type)
64 	: QObject()
65 {
66 	commonInit(type);
67 	m_modelPartShared = new ModelPartShared(domDocument, path);
68     m_modelPartShared->addOwner(this);
69 }
70 
commonInit(ItemType type)71 void ModelPart::commonInit(ItemType type) {
72 	m_type = type;
73 	m_locationFlags = 0;
74 	m_indexSynched = false;
75 }
76 
~ModelPart()77 ModelPart::~ModelPart() {
78 	//DebugDialog::debug(QString("deleting modelpart %1 %2").arg((long) this, 0, 16).arg(m_index));
79 
80 	clearOldInstanceTitle(m_instanceTitle);
81 
82 	InstanceTitleIncrementHash * itih = AllInstanceTitleIncrements.value(this);
83 	if (itih) {
84 		AllInstanceTitleIncrements.remove(this);
85 		foreach (ModelPartList * list, itih->values()) {
86 			delete list;
87 		}
88 		delete itih;
89 	}
90 
91 	foreach (Connector * connector, m_connectorHash.values()) {
92 		delete connector;
93 	}
94 	m_connectorHash.clear();
95 
96 	clearBuses();
97 }
98 
moduleID() const99 const QString & ModelPart::moduleID() const {
100 	if (m_modelPartShared != NULL) return m_modelPartShared->moduleID();
101 
102 	return ___emptyString___;
103 }
104 
label()105 const QString & ModelPart::label() {
106 	if (m_modelPartShared != NULL) return m_modelPartShared->label();
107 
108 	return ___emptyString___;
109 }
110 
author()111 const QString & ModelPart::author() {
112 	if (m_modelPartShared != NULL) return m_modelPartShared->author();
113 
114 	return ___emptyString___;
115 }
116 
taxonomy()117 const QString & ModelPart::taxonomy() {
118 	if (m_modelPartShared != NULL) return m_modelPartShared->taxonomy();
119 
120 	return ___emptyString___;
121 }
122 
uri()123 const QString & ModelPart::uri() {
124 	if (m_modelPartShared != NULL) return m_modelPartShared->uri();
125 
126 	return ___emptyString___;
127 }
128 
date()129 const QDate & ModelPart::date() {
130 	if (m_modelPartShared != NULL) return m_modelPartShared->date();
131 
132 	static QDate tempDate;
133 	tempDate = QDate::currentDate();
134 	return tempDate;
135 }
136 
setItemType(ItemType t)137 void ModelPart::setItemType(ItemType t) {
138 	m_type = t;
139 }
140 
copy(ModelPart * modelPart)141 void ModelPart::copy(ModelPart * modelPart) {
142 	if (modelPart == NULL) return;
143 
144 	m_type = modelPart->itemType();
145 	m_modelPartShared = modelPart->modelPartShared();
146     if (m_modelPartShared) m_modelPartShared->addOwner(this);
147 	m_locationFlags = modelPart->m_locationFlags;
148 }
149 
copyNew(ModelPart * modelPart)150 void ModelPart::copyNew(ModelPart * modelPart) {
151 	copy(modelPart);
152 }
153 
copyStuff(ModelPart * modelPart)154 void ModelPart::copyStuff(ModelPart * modelPart) {
155 	modelPartShared()->copy(modelPart->modelPartShared());
156 }
157 
modelPartShared()158 ModelPartShared * ModelPart::modelPartShared() {
159 	if(!m_modelPartShared) {
160 		m_modelPartShared = new ModelPartShared();
161         m_modelPartShared->addOwner(this);
162 	}
163 	return m_modelPartShared;
164 }
165 
modelPartSharedRoot()166 ModelPartSharedRoot * ModelPart::modelPartSharedRoot() {
167 	return qobject_cast<ModelPartSharedRoot *>(m_modelPartShared);
168 }
169 
setModelPartShared(ModelPartShared * modelPartShared)170 void ModelPart::setModelPartShared(ModelPartShared * modelPartShared) {
171 	m_modelPartShared = modelPartShared;
172     if (modelPartShared) m_modelPartShared->addOwner(this);
173 }
174 
addViewItem(ItemBase * item)175 void ModelPart::addViewItem(ItemBase * item) {
176 	m_viewItems.append(item);
177 }
178 
removeViewItem(ItemBase * item)179 void ModelPart::removeViewItem(ItemBase * item) {
180 	m_viewItems.removeOne(item);
181 }
182 
viewItem(QGraphicsScene * scene)183 ItemBase * ModelPart::viewItem(QGraphicsScene * scene) {
184 	foreach (ItemBase * itemBase, m_viewItems) {
185 		if (itemBase->scene() == scene) return itemBase;
186 	}
187 
188 	return NULL;
189 }
190 
viewItem(ViewLayer::ViewID viewID)191 ItemBase * ModelPart::viewItem(ViewLayer::ViewID viewID) {
192 	foreach (ItemBase * itemBase, m_viewItems) {
193 		if (itemBase->viewID() == viewID) return itemBase;
194 	}
195 
196 	return NULL;
197 }
198 
saveInstances(const QString & fileName,QXmlStreamWriter & streamWriter,bool startDocument)199 void ModelPart::saveInstances(const QString & fileName, QXmlStreamWriter & streamWriter, bool startDocument) {
200 	if (startDocument) {
201 		streamWriter.writeStartDocument();
202     	streamWriter.writeStartElement("module");
203 		streamWriter.writeAttribute("fritzingVersion", Version::versionString());
204 		ModelPartSharedRoot * root = modelPartSharedRoot();
205 		if (root) {
206 			if (!root->icon().isEmpty()) {
207 				streamWriter.writeAttribute("icon", root->icon());
208 			}
209 			if (!root->searchTerm().isEmpty()) {
210 				streamWriter.writeAttribute("search", root->searchTerm());
211 			}
212 		}
213 		QString title = this->title();
214 		if(!title.isNull() && !title.isEmpty()) {
215 			streamWriter.writeTextElement("title",title);
216 		}
217 
218 		emit startSaveInstances(fileName, this, streamWriter);
219 
220 		streamWriter.writeStartElement("instances");
221 	}
222 
223 	if (parent() != NULL) {  // m_viewItems.size() > 0
224 		saveInstance(streamWriter);
225 	}
226 
227 	QList<QObject *> children = this->children();
228 	if(m_orderedChildren.count() > 0) {
229 		children = m_orderedChildren;
230 	}
231 
232 	QList<QObject *>::const_iterator i;
233 	for (i = children.constBegin(); i != children.constEnd(); ++i) {
234 		ModelPart* mp = qobject_cast<ModelPart *>(*i);
235 		if (mp == NULL) continue;
236 
237 		mp->saveInstances(fileName, streamWriter, false);
238 	}
239 
240 
241 	if (startDocument) {
242 		streamWriter.writeEndElement();	  //  instances
243 		streamWriter.writeEndElement();   //  module
244 		streamWriter.writeEndDocument();
245 	}
246 }
247 
saveInstance(QXmlStreamWriter & streamWriter)248 void ModelPart::saveInstance(QXmlStreamWriter & streamWriter)
249 {
250 	if (localProp("ratsnest").toBool()) {
251 		return;				// don't save virtual wires
252 	}
253 
254 	streamWriter.writeStartElement("instance");
255 	if (m_modelPartShared != NULL) {
256 		QString moduleIdRef = m_modelPartShared->moduleID();
257         moduleIdRef.remove(PartFactory::OldSchematicPrefix);
258 		streamWriter.writeAttribute("moduleIdRef", moduleIdRef);
259 		streamWriter.writeAttribute("modelIndex", QString::number(m_index));
260 		streamWriter.writeAttribute("path", m_modelPartShared->path());
261         if (m_modelPartShared->flippedSMD()) {
262 			streamWriter.writeAttribute("flippedSMD", "true");
263 		}
264 	}
265 
266 	bool writeLocal = false;
267 	foreach (Connector * connector, this->connectors()) {
268 		if (!connector->connectorLocalName().isEmpty()) {
269 			writeLocal = true;
270 			break;
271 		}
272 	}
273 
274 	if (writeLocal) {
275 		streamWriter.writeStartElement("localConnectors");
276 		foreach (Connector * connector, this->connectors()) {
277 			if (!connector->connectorLocalName().isEmpty()) {
278 				streamWriter.writeStartElement("localConnector");
279 				streamWriter.writeAttribute("id", connector->connectorSharedID());
280 				streamWriter.writeAttribute("name", TextUtils::stripNonValidXMLCharacters(TextUtils::escapeAnd(connector->connectorLocalName())));
281 				streamWriter.writeEndElement();
282 			}
283 		}
284 		streamWriter.writeEndElement();
285 	}
286 
287 	foreach (QByteArray byteArray, dynamicPropertyNames()) {
288 		streamWriter.writeStartElement("property");
289 		streamWriter.writeAttribute("name",  byteArray.data());
290 		streamWriter.writeAttribute("value", property(byteArray.data()).toString());
291 		streamWriter.writeEndElement();
292 	}
293 
294 	QString title = instanceTitle();
295 	if(!title.isNull() && !title.isEmpty()) {
296 		writeTag(streamWriter,"title",title);
297 	}
298 
299 	QString text = instanceText();
300 	if(!text.isNull() && !text.isEmpty()) {
301 		streamWriter.writeStartElement("text");
302 		streamWriter.writeCharacters(text);
303 		streamWriter.writeEndElement();
304 	}
305 
306 	// tell the views to write themselves out
307 	streamWriter.writeStartElement("views");
308 	foreach (ItemBase * itemBase, m_viewItems) {
309 		itemBase->saveInstance(streamWriter);
310 	}
311 	streamWriter.writeEndElement();		// views
312 	streamWriter.writeEndElement();		//instance
313 }
314 
writeTag(QXmlStreamWriter & streamWriter,QString tagName,QString tagValue)315 void ModelPart::writeTag(QXmlStreamWriter & streamWriter, QString tagName, QString tagValue) {
316 	if(!tagValue.isEmpty()) {
317 		streamWriter.writeTextElement(tagName,tagValue);
318 	}
319 }
320 
writeNestedTag(QXmlStreamWriter & streamWriter,QString tagName,const QStringList & values,QString childTag)321 void ModelPart::writeNestedTag(QXmlStreamWriter & streamWriter, QString tagName, const QStringList &values, QString childTag) {
322 	if(values.count() > 0) {
323 		streamWriter.writeStartElement(tagName);
324 		for(int i=0; i<values.count(); i++) {
325 			writeTag(streamWriter, childTag, values[i]);
326 		}
327 		streamWriter.writeEndElement();
328 	}
329 }
330 
writeNestedTag(QXmlStreamWriter & streamWriter,QString tagName,const QHash<QString,QString> & values,QString childTag,QString attrName)331 void ModelPart::writeNestedTag(QXmlStreamWriter & streamWriter, QString tagName, const QHash<QString,QString> &values, QString childTag, QString attrName) {
332 	streamWriter.writeStartElement(tagName);
333 	for(int i=0; i<values.keys().count(); i++) {
334 		streamWriter.writeStartElement(childTag);
335 		QString key = values.keys()[i];
336 		streamWriter.writeAttribute(attrName,key);
337 		streamWriter.writeCharacters(values[key]);
338 		streamWriter.writeEndElement();
339 	}
340 	streamWriter.writeEndElement();
341 }
342 
saveAsPart(QXmlStreamWriter & streamWriter,bool startDocument)343 void ModelPart::saveAsPart(QXmlStreamWriter & streamWriter, bool startDocument) {
344 	if (startDocument) {
345 		streamWriter.writeStartDocument();
346     	streamWriter.writeStartElement("module");
347 		streamWriter.writeAttribute("fritzingVersion", Version::versionString());
348         QString moduleID = m_modelPartShared->moduleID();
349         moduleID.remove(PartFactory::OldSchematicPrefix);
350 		streamWriter.writeAttribute("moduleId", moduleID);
351     	writeTag(streamWriter,"version",m_modelPartShared->version());
352     	writeTag(streamWriter,"author",m_modelPartShared->author());
353     	writeTag(streamWriter,"title",title());
354     	writeTag(streamWriter,"label",m_modelPartShared->label());
355     	writeTag(streamWriter,"date",m_modelPartShared->dateAsStr());
356 
357     	writeNestedTag(streamWriter,"tags",m_modelPartShared->tags(),"tag");
358     	writeNestedTag(streamWriter,"properties",m_modelPartShared->properties(),"property","name");
359 
360     	writeTag(streamWriter,"taxonomy",m_modelPartShared->taxonomy());
361     	writeTag(streamWriter,"description",m_modelPartShared->description());
362 
363         QString spice = m_modelPartShared->spice();
364         if (!spice.isEmpty()) {
365             streamWriter.writeStartElement("spice");
366             QStringList lines = spice.split("\r",QString::SkipEmptyParts);
367             foreach (QString line, lines) {
368                 writeTag(streamWriter, "line", line);
369             }
370             QString spiceModel = m_modelPartShared->spiceModel();
371             if (!spiceModel.isEmpty()) {
372                 lines = spiceModel.split("\r",QString::SkipEmptyParts);
373                 foreach (QString line, lines) {
374                     writeTag(streamWriter, "model", line);
375                 }
376             }
377             streamWriter.writeEndElement();
378         }
379 
380 
381     	writeTag(streamWriter,"spice",m_modelPartShared->spice());
382     	writeTag(streamWriter,"url",m_modelPartShared->url());
383 	}
384 
385 	if (m_viewItems.size() > 0) {
386 		if (startDocument) {
387 			streamWriter.writeStartElement("views");
388 		}
389 		for (int i = 0; i < m_viewItems.size(); i++) {
390 			ItemBase * item = m_viewItems[i];
391 			item->writeXml(streamWriter);
392 		}
393 
394 		if(startDocument) {
395 			streamWriter.writeEndElement();
396 		}
397 
398 		streamWriter.writeStartElement("connectors");
399 		const QList< QPointer<ConnectorShared> > connectors = m_modelPartShared->connectorsShared();
400 		for (int i = 0; i < connectors.count(); i++) {
401 			Connector * connector = new Connector(connectors[i], this);
402 			connector->saveAsPart(streamWriter);
403 			delete connector;
404 		}
405 		streamWriter.writeEndElement();
406 	}
407 
408 	QList<QObject *>::const_iterator i;
409     for (i = children().constBegin(); i != children().constEnd(); ++i) {
410 		ModelPart * mp = qobject_cast<ModelPart *>(*i);
411 		if (mp == NULL) continue;
412 
413 		mp->saveAsPart(streamWriter, false);
414 	}
415 
416 	if (startDocument) {
417 		streamWriter.writeEndElement();
418 		streamWriter.writeEndElement();
419 		streamWriter.writeEndDocument();
420 	}
421 }
422 
initConnectors(bool force)423 void ModelPart::initConnectors(bool force) {
424 	if(m_modelPartShared == NULL) return;
425 
426 	if(force) {
427 		foreach (Connector * connector, m_connectorHash.values()) {
428 			// due to craziness in the parts editor
429 			// m_deletedConnectors.append(connector);
430 			delete connector;
431 		}
432 		m_connectorHash.clear();
433 		clearBuses();
434 	}
435 	if(m_connectorHash.count() > 0) return;		// already done
436 
437 	m_modelPartShared->initConnectors();
438 	foreach (ConnectorShared * connectorShared, m_modelPartShared->connectorsShared()) {
439 		Connector * connector = new Connector(connectorShared, this);
440 		m_connectorHash.insert(connectorShared->id(), connector);
441 	}
442 	initBuses();
443 }
444 
clearBuses()445 void ModelPart::clearBuses() {
446 	foreach (Bus * bus, m_busHash.values()) {
447 		delete bus;
448 	}
449 	m_busHash.clear();
450 }
451 
initBuses()452 void ModelPart::initBuses() {
453 	foreach (Connector * connector, m_connectorHash.values()) {
454 		BusShared * busShared = connector->connectorShared()->bus();
455 		if (busShared != NULL) {
456 			Bus * bus = m_busHash.value(busShared->id());
457 			if (bus == NULL) {
458 				bus = new Bus(busShared, this);
459 				m_busHash.insert(busShared->id(), bus);
460 			}
461 			connector->setBus(bus);
462 			bus->addConnector(connector);
463 		}
464 	}
465 }
466 
connectors()467 const QHash<QString, QPointer<Connector> > & ModelPart::connectors() {
468 	return m_connectorHash;
469 }
470 
modelIndex()471 long ModelPart::modelIndex() {
472 	return m_index;
473 }
474 
setModelIndex(long index)475 void ModelPart::setModelIndex(long index) {
476 	m_index = index;
477 	updateIndex(index);
478 }
479 
setModelIndexFromMultiplied(long multiplied)480 void ModelPart::setModelIndexFromMultiplied(long multiplied) {
481 	if (m_indexSynched) {
482 		// this is gross.  m_index should always be itemBase->id() / ModelPart::indexMultiplier
483 		// but sometimes multiple parts reuse the same model part, so this makes sure we don't overwrite
484 		// when temporarily reusing a modelpart.  Eventually always create a new model part and get rid of modelIndex
485 		if (m_index != multiplied / ModelPart::indexMultiplier) {
486 			//DebugDialog::debug("temporary model part?");
487 		}
488 
489 		return;
490 	}
491 
492 	m_indexSynched = true;
493 	setModelIndex(multiplied / ModelPart::indexMultiplier);
494 }
495 
updateIndex(long index)496 void ModelPart::updateIndex(long index)
497 {
498 	if (index >= m_nextIndex) {
499 		m_nextIndex = index + 1;
500 	}
501 }
502 
nextIndex()503 long ModelPart::nextIndex() {
504 	return m_nextIndex++;
505 }
506 
setInstanceDomElement(const QDomElement & domElement)507 void ModelPart::setInstanceDomElement(const QDomElement & domElement) {
508 	//DebugDialog::debug(QString("model part instance %1").arg((long) this, 0, 16));
509 	m_instanceDomElement = domElement;
510 }
511 
instanceDomElement()512 const QDomElement & ModelPart::instanceDomElement() {
513 	return m_instanceDomElement;
514 }
515 
fritzingVersion()516 const QString & ModelPart::fritzingVersion() {
517 
518 	if (m_modelPartShared != NULL) return m_modelPartShared->fritzingVersion();
519 
520 	return ___emptyString___;
521 }
522 
title()523 const QString & ModelPart::title() {
524 	if (!m_localTitle.isEmpty()) return m_localTitle;
525 
526 	if (m_modelPartShared != NULL) return m_modelPartShared->title();
527 
528 	return m_localTitle;
529 }
530 
setLocalTitle(const QString & localTitle)531 void ModelPart::setLocalTitle(const QString & localTitle) {
532 	m_localTitle = localTitle;
533 }
534 
version()535 const QString & ModelPart::version() {
536 	if (m_modelPartShared != NULL) return m_modelPartShared->version();
537 
538 	return ___emptyString___;
539 }
540 
path()541 const QString & ModelPart::path() {
542 	if (m_modelPartShared != NULL) return m_modelPartShared->path();
543 
544 	return ___emptyString___;
545 }
546 
description()547 const QString & ModelPart::description() {
548 	if (m_modelPartShared != NULL) return m_modelPartShared->description();
549 
550 	return ___emptyString___;
551 }
552 
spice()553 const QString & ModelPart::spice() {
554 	if (m_modelPartShared != NULL) return m_modelPartShared->spice();
555 
556 	return ___emptyString___;
557 }
558 
spiceModel()559 const QString & ModelPart::spiceModel() {
560 	if (m_modelPartShared != NULL) return m_modelPartShared->spiceModel();
561 
562 	return ___emptyString___;
563 }
564 
url()565 const QString & ModelPart::url() {
566 	if (m_modelPartShared != NULL) return m_modelPartShared->url();
567 
568 	return ___emptyString___;
569 }
570 
tags()571 const QStringList & ModelPart::tags() {
572 	if (m_modelPartShared != NULL) return m_modelPartShared->tags();
573 
574 	return ___emptyStringList___;
575 }
576 
properties() const577 const QHash<QString,QString> & ModelPart::properties() const {
578 	if (m_modelPartShared != NULL) return m_modelPartShared->properties();
579 
580 	return ___emptyStringHash___;
581 }
582 
getConnector(const QString & id)583 Connector * ModelPart::getConnector(const QString & id) {
584 	return m_connectorHash.value(id);
585 }
586 
buses()587 const QHash<QString, QPointer<Bus> > & ModelPart::buses() {
588 	return  m_busHash;
589 }
590 
bus(const QString & busID)591 Bus * ModelPart::bus(const QString & busID) {
592 	return m_busHash.value(busID);
593 }
594 
ignoreTerminalPoints()595 bool ModelPart::ignoreTerminalPoints() {
596 	if (m_modelPartShared != NULL) return m_modelPartShared->ignoreTerminalPoints();
597 
598 	return true;
599 }
600 
isCore()601 bool ModelPart::isCore() {
602 	return (m_locationFlags & CoreFlag) != 0;
603 }
604 
setCore(bool core)605 void ModelPart::setCore(bool core) {
606 	setLocationFlag(core, CoreFlag);
607 }
608 
isContrib()609 bool ModelPart::isContrib() {
610 	return (m_locationFlags & ContribFlag) != 0;
611 }
612 
setContrib(bool contrib)613 void ModelPart::setContrib(bool contrib) {
614 	setLocationFlag(contrib, ContribFlag);
615 }
616 
isAlien()617 bool ModelPart::isAlien() {
618 	return (m_locationFlags & AlienFlag) != 0;;
619 }
620 
setAlien(bool alien)621 void ModelPart::setAlien(bool alien) {
622 	setLocationFlag(alien, AlienFlag);
623 }
isInBin()624 bool ModelPart::isInBin() {
625 	return (m_locationFlags & InBinFlag) != 0;;
626 }
627 
setInBin(bool inBin)628 void ModelPart::setInBin(bool inBin) {
629 	setLocationFlag(inBin, InBinFlag);
630 }
631 
isFzz()632 bool ModelPart::isFzz() {
633 	return (m_locationFlags & FzzFlag) != 0;;
634 }
635 
setFzz(bool fzz)636 void ModelPart::setFzz(bool fzz) {
637 	setLocationFlag(fzz, FzzFlag);
638 }
639 
setLocationFlag(bool setting,LocationFlag flag)640 void ModelPart::setLocationFlag(bool setting, LocationFlag flag) {
641 	if (setting) {
642 		m_locationFlags |= flag;
643 	}
644 	else {
645 		m_locationFlags &= ~flag;
646 	}
647 }
648 
hasViewID(ViewLayer::ViewID viewID)649 bool ModelPart::hasViewID(ViewLayer::ViewID viewID) {
650     if (m_modelPartShared) return m_modelPartShared->hasViewID(viewID);
651 
652     return false;
653 
654 }
655 
canFlipVertical(ViewLayer::ViewID viewID)656 bool ModelPart::canFlipVertical(ViewLayer::ViewID viewID) {
657     if (m_modelPartShared) return m_modelPartShared->canFlipVertical(viewID);
658 
659     return false;
660 
661 }
662 
canFlipHorizontal(ViewLayer::ViewID viewID)663 bool ModelPart::canFlipHorizontal(ViewLayer::ViewID viewID) {
664     if (m_modelPartShared) return m_modelPartShared->canFlipHorizontal(viewID);
665 
666     return false;
667 }
668 
viewLayers(ViewLayer::ViewID viewID)669 LayerList ModelPart::viewLayers(ViewLayer::ViewID viewID) {
670     if (m_modelPartShared) return m_modelPartShared->viewLayers(viewID);
671 
672     LayerList layerList;
673     return layerList;
674 }
675 
imageFileName(ViewLayer::ViewID viewID)676 QString ModelPart::imageFileName(ViewLayer::ViewID viewID) {
677     if (m_modelPartShared) return m_modelPartShared->imageFileName(viewID);
678 
679     return "";
680 }
681 
imageFileName(ViewLayer::ViewID viewID,ViewLayer::ViewLayerID viewLayerID)682 QString ModelPart::imageFileName(ViewLayer::ViewID viewID, ViewLayer::ViewLayerID viewLayerID) {
683     if (m_modelPartShared) return m_modelPartShared->imageFileName(viewID, viewLayerID);
684 
685     return "";
686 }
687 
anySticky(ViewLayer::ViewID viewID)688 bool ModelPart::anySticky(ViewLayer::ViewID viewID) {
689     if (m_modelPartShared) return m_modelPartShared->anySticky(viewID);
690 
691     return false;
692 }
693 
getAllParts()694 QList<ModelPart*> ModelPart::getAllParts() {
695 	QList<ModelPart*> retval;
696 	QList<QObject *>::const_iterator i;
697 	for (i = children().constBegin(); i != children().constEnd(); ++i) {
698 		ModelPart* mp = qobject_cast<ModelPart *>(*i);
699 		if (mp == NULL) continue;
700 		retval << mp;
701 	}
702 
703 	return retval;
704 }
705 
getAllNonCoreParts()706 QList<ModelPart*> ModelPart::getAllNonCoreParts() {
707 	QList<ModelPart*> retval;
708 	QList<QObject *>::const_iterator i;
709 	for (i = children().constBegin(); i != children().constEnd(); ++i) {
710 		ModelPart* mp = qobject_cast<ModelPart *>(*i);
711 		if (mp == NULL) continue;
712 
713 		if(!mp->isCore()) {
714 			retval << mp;
715 		}
716 	}
717 
718 	return retval;
719 }
720 
hasViewID(long id)721 bool ModelPart::hasViewID(long id) {
722 	foreach (ItemBase * item, m_viewItems) {
723 		if (item->id() == id) return true;
724 	}
725 
726 	return false;
727 }
728 
instanceTitle() const729 const QString & ModelPart::instanceTitle() const {
730 	return m_instanceTitle;
731 }
732 
instanceText()733 const QString & ModelPart::instanceText() {
734 	return m_instanceText;
735 }
736 
setInstanceText(QString text)737 void ModelPart::setInstanceText(QString text) {
738 	m_instanceText = text;
739 }
740 
clearOldInstanceTitle(const QString & title)741 void ModelPart::clearOldInstanceTitle(const QString & title)
742 {
743 	InstanceTitleIncrementHash * itih = NULL;
744 	if (parent() == NULL) {
745 		itih = &NullInstanceTitleIncrements;
746 	}
747 	else {
748 		itih = AllInstanceTitleIncrements.value(parent(), NULL);
749 	}
750 
751 	if (itih == NULL) return;
752 
753 	//DebugDialog::debug(QString("clearing title:%1 ix:%2").arg(title).arg(modelPart->modelIndex()));
754 	QString prefix = title;
755 	int ix = InstanceTitleRegExp.indexIn(title);
756 	if (ix >= 0) {
757 		prefix = InstanceTitleRegExp.cap(1);
758 	}
759 	ModelPartList * modelParts = itih->value(prefix, NULL);
760 	if (modelParts) {
761 		modelParts->removeOne(this);
762 		//DebugDialog::debug(QString("\tc:%1").arg(modelParts->count()));
763 	}
764 }
765 
ensureInstanceTitleIncrements(const QString & prefix)766 ModelPartList * ModelPart::ensureInstanceTitleIncrements(const QString & prefix)
767 {
768 	InstanceTitleIncrementHash * itih = NULL;
769 	if (parent() == NULL) {
770 		itih = &NullInstanceTitleIncrements;
771 	}
772 	else {
773 		itih = AllInstanceTitleIncrements.value(parent(), NULL);
774 		if (itih == NULL) {
775 			itih = new InstanceTitleIncrementHash;
776 			AllInstanceTitleIncrements.insert(parent(), itih);
777 		}
778 	}
779 
780 	ModelPartList * modelParts = itih->value(prefix, NULL);
781 	if (modelParts == NULL) {
782 		modelParts =  new ModelPartList;
783 		itih->insert(prefix, modelParts);
784 	}
785 	return modelParts;
786 }
787 
setInstanceTitle(QString title,bool initial)788 void ModelPart::setInstanceTitle(QString title, bool initial) {
789     if (initial) {
790         if (setSubpartInstanceTitle()) return;
791     }
792 
793     if (title.compare(m_instanceTitle) == 0) return;
794 
795 	clearOldInstanceTitle(m_instanceTitle);
796 
797 	m_instanceTitle = title;
798 
799 	QString prefix = title;
800 	int ix = InstanceTitleRegExp.indexIn(title);
801 	if (ix >= 0) {
802 		prefix = InstanceTitleRegExp.cap(1);
803 		ModelPartList * modelParts = ensureInstanceTitleIncrements(prefix);
804 		modelParts->append(this);
805 	}
806 	//DebugDialog::debug(QString("adding title:%1 ix:%2 c:%3").arg(title).arg(modelIndex()).arg(modelParts->count()));
807 
808     if (m_modelPartShared && m_modelPartShared->hasSubparts()) {
809         if (m_viewItems.count() > 0) {
810             ItemBase * itemBase = m_viewItems.last();
811             if (itemBase) {
812                 foreach (ItemBase * subpart, itemBase->subparts()) {
813                     subpart->setInstanceTitle("", true);   // will end up calling setSubpartInstanceTitle()
814                 }
815             }
816         }
817     }
818 }
819 
setSubpartInstanceTitle()820 bool ModelPart::setSubpartInstanceTitle() {
821     if (m_modelPartShared == NULL) return false;
822     if (m_modelPartShared->superpart() == NULL) return false;
823     if (m_viewItems.count() <= 0) return false;
824 
825     ItemBase * itemBase = m_viewItems.last();
826     if (itemBase == NULL) return false;
827 
828     itemBase = itemBase->superpart();
829     if (itemBase == NULL) return false;
830 
831     QString superTitle = itemBase->instanceTitle();
832     if (superTitle.isEmpty()) return false;
833 
834     QString label = m_modelPartShared->label();
835     if (label.isEmpty()) return false;
836 
837     m_instanceTitle = superTitle + "_" + label;
838     return true;
839 }
840 
getNextTitle(const QString & title)841 QString ModelPart::getNextTitle(const QString & title) {
842 	QString prefix = title;
843 	int ix = InstanceTitleRegExp.indexIn(title);
844 	if (ix >= 0) {
845 		prefix = InstanceTitleRegExp.cap(1);
846 	}
847 	else {
848 		bool allDigits = true;
849 		foreach (QChar c, title) {
850 			if (!c.isDigit()) {
851 				allDigits = false;
852 				break;
853 			}
854 		}
855 		if (allDigits) {
856 			return title;
857 		}
858 	}
859 
860 	// TODO: if this were a sorted list,
861 	ModelPartList * modelParts = ensureInstanceTitleIncrements(prefix);
862 	int highestSoFar = 0;
863 	bool gotNull = false;
864 	foreach (ModelPart * modelPart, *modelParts) {
865 		if (modelPart == NULL) {
866 			gotNull = true;
867 			continue;
868 		}
869 
870 		QString title = modelPart->instanceTitle();
871 		title.remove(0, prefix.length());
872 		int count = title.toInt();			// returns zero on failure
873 		if (count > highestSoFar) {
874 			highestSoFar = count;
875 		}
876 	}
877 
878 	if (gotNull) {
879 		modelParts->removeAll(NULL);
880 	}
881 
882 	//DebugDialog::debug(QString("returning increment %1, %2").arg(prefix).arg(highestSoFar + 1));
883 	return QString("%1%2").arg(prefix).arg(highestSoFar + 1);
884 }
885 
setOrderedChildren(QList<QObject * > children)886 void ModelPart::setOrderedChildren(QList<QObject*> children) {
887 	m_orderedChildren = children;
888 }
889 
setLocalProp(const char * name,const QVariant & value)890 void ModelPart::setLocalProp(const char * name, const QVariant & value) {
891     //DebugDialog::debug(QString("mp set prop %1 %2").arg(name).arg(value.toString()));
892 	QObject::setProperty(name, value);
893 }
894 
localProp(const char * name) const895 QVariant ModelPart::localProp(const char * name) const {
896 	return property(name);
897 }
898 
setLocalProp(const QString & name,const QVariant & value)899 void ModelPart::setLocalProp(const QString & name, const QVariant & value) {
900 	QByteArray b = name.toLatin1();
901 	setLocalProp(b.data(), value);
902 }
903 
localProp(const QString & name) const904 QVariant ModelPart::localProp(const QString & name) const {
905 	QByteArray b = name.toLatin1();
906 	return localProp(b.data());
907 }
908 
possibleFolders()909 const QStringList & ModelPart::possibleFolders() {
910 	if (m_possibleFolders.count() == 0) {
911 		m_possibleFolders << "core" << "obsolete" << "contrib" << "user";
912 	}
913 
914 	return m_possibleFolders;
915 }
916 
replacedby()917 const QString & ModelPart::replacedby() {
918 	if (m_modelPartShared != NULL) return m_modelPartShared->replacedby();
919 
920 	return ___emptyString___;
921 }
922 
isObsolete()923 bool ModelPart::isObsolete() {
924 	if (m_modelPartShared != NULL) return !m_modelPartShared->replacedby().isEmpty();
925 
926 	return false;
927 }
928 
flippedSMD()929 bool ModelPart::flippedSMD() {
930 	if (m_modelPartShared != NULL) {
931 		return m_modelPartShared->flippedSMD();
932 	}
933 
934 	return false;
935 }
936 
needsCopper1()937 bool ModelPart::needsCopper1() {
938 	if (m_modelPartShared != NULL) {
939 		return m_modelPartShared->needsCopper1();
940 	}
941 
942 	return false;
943 }
944 
hasViewFor(ViewLayer::ViewID viewID)945 bool ModelPart::hasViewFor(ViewLayer::ViewID viewID) {
946 	if (m_modelPartShared == NULL) return false;
947 
948 	return m_modelPartShared->hasViewFor(viewID);
949 }
950 
hasViewFor(ViewLayer::ViewID viewID,ViewLayer::ViewLayerID viewLayerID)951 bool ModelPart::hasViewFor(ViewLayer::ViewID viewID, ViewLayer::ViewLayerID viewLayerID) {
952 	if (m_modelPartShared == NULL) return false;
953 
954 	return m_modelPartShared->hasViewFor(viewID, viewLayerID);
955 }
956 
hasBaseNameFor(ViewLayer::ViewID viewID)957 QString ModelPart::hasBaseNameFor(ViewLayer::ViewID viewID) {
958 	if (m_modelPartShared == NULL) return ___emptyString___;
959 
960 	return m_modelPartShared->hasBaseNameFor(viewID);
961 }
962 
displayKeys()963 const QStringList & ModelPart::displayKeys() {
964 	if (m_modelPartShared == NULL) return ___emptyStringList___;
965 
966 	return m_modelPartShared->displayKeys();
967 }
968 
itemType() const969 ModelPart::ItemType ModelPart::itemType() const
970 {
971 	return m_type;
972 };
973 
setConnectorLocalName(const QString & id,const QString & name)974 void ModelPart::setConnectorLocalName(const QString & id, const QString & name)
975 {
976 	if (id.isEmpty()) return;
977 	Connector * connector = m_connectorHash.value(id, NULL);
978 	if (connector) {
979 		connector->setConnectorLocalName(name);
980 	}
981 }
982 
connectorLocalName(const QString & id)983 QString ModelPart::connectorLocalName(const QString & id)
984 {
985 	if (id.isEmpty()) return "";
986 
987 	Connector * connector = m_connectorHash.value(id, NULL);
988 	if (connector) {
989 		return connector->connectorLocalName();
990 	}
991 
992 	return "";
993 }
994 
family()995 QString ModelPart::family(){
996 	if (m_modelPartShared) return m_modelPartShared->family();
997 
998 	return "";
999 }
1000 
hasViewItems()1001 bool ModelPart::hasViewItems() {
1002 	return (m_viewItems.count() > 0);
1003 }
1004 
setDBID(qulonglong dbid)1005 void ModelPart::setDBID(qulonglong dbid) {
1006     if (m_modelPartShared) m_modelPartShared->setDBID(dbid);
1007 }
1008 
dbid()1009 qulonglong ModelPart::dbid() {
1010     if (m_modelPartShared) return m_modelPartShared->dbid();
1011 
1012     return 0;
1013 }
1014 
viewImages()1015 const QList<ViewImage *> ModelPart::viewImages() {
1016     if (m_modelPartShared) return m_modelPartShared->viewImages();
1017 
1018     return EmptyViewImages;
1019 }
1020 
setViewImage(ViewImage * viewImage)1021 void ModelPart::setViewImage(ViewImage * viewImage) {
1022     if (m_modelPartShared) m_modelPartShared->setViewImage(viewImage);
1023 }
1024 
setTag(const QString & tag)1025 void ModelPart::setTag(const QString & tag)
1026 {
1027     if (m_modelPartShared) m_modelPartShared->setTag(tag);
1028 }
1029 
setProperty(const QString & name,const QString & value,bool showInLabel)1030 void ModelPart::setProperty(const QString & name, const QString &value, bool showInLabel)
1031 {
1032     if (m_modelPartShared) m_modelPartShared->setProperty(name, value, showInLabel);
1033 }
1034 
showInLabel(const QString & propertyName)1035 bool ModelPart::showInLabel(const QString & propertyName) {
1036     if (m_modelPartShared) return m_modelPartShared->showInLabel(propertyName);
1037 
1038     return false;
1039 }
1040 
addConnector(Connector * connector)1041 void ModelPart::addConnector(Connector * connector) {
1042     m_connectorHash.insert(connector->connectorSharedID(), connector);
1043 
1044     if (m_modelPartShared) m_modelPartShared->addConnector(connector->connectorShared());
1045 }
1046 
flipSMDAnd()1047 void ModelPart::flipSMDAnd() {
1048     if (m_modelPartShared) m_modelPartShared->flipSMDAnd();
1049 }
1050 
setImageFileName(ViewLayer::ViewID viewID,const QString & filename)1051 void ModelPart::setImageFileName(ViewLayer::ViewID viewID, const QString & filename) {
1052     if (m_modelPartShared) m_modelPartShared->setImageFileName(viewID, filename);
1053 }
1054 
lookForZeroConnector()1055 void ModelPart::lookForZeroConnector() {
1056     if (m_modelPartShared) m_modelPartShared->lookForZeroConnector();
1057 }
1058 
hasZeroConnector()1059 bool ModelPart::hasZeroConnector() {
1060     if (m_modelPartShared) return m_modelPartShared->hasZeroConnector();
1061 
1062     return false;
1063 }
1064 
killViewItems()1065 void ModelPart::killViewItems() {
1066 	foreach (ItemBase * itemBase, m_viewItems) {
1067 		if (itemBase) delete itemBase;
1068 	}
1069 
1070     m_viewItems.clear();
1071 }
1072 
hasSubparts()1073 bool ModelPart::hasSubparts() {
1074     if (m_modelPartShared) return m_modelPartShared->hasSubparts();
1075 
1076     return false;
1077 }
1078 
setSubpartID(const QString & id)1079 void ModelPart::setSubpartID(const QString & id) {
1080     if (m_modelPartShared) m_modelPartShared->setSubpartID(id);
1081 }
1082