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: 6984 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-22 23:44:56 +0200 (Mo, 22. Apr 2013) $
24
25 ********************************************************************/
26
27 #include "mysterypart.h"
28 #include "../utils/graphicsutils.h"
29 #include "../utils/familypropertycombobox.h"
30 #include "../utils/schematicrectconstants.h"
31 #include "../fsvgrenderer.h"
32 #include "../sketch/infographicsview.h"
33 #include "../commands.h"
34 #include "../utils/textutils.h"
35 #include "../layerattributes.h"
36 #include "partlabel.h"
37 #include "pinheader.h"
38 #include "partfactory.h"
39 #include "../connectors/connectoritem.h"
40 #include "../svg/svgfilesplitter.h"
41
42 #include <QDomNodeList>
43 #include <QDomDocument>
44 #include <QDomElement>
45 #include <QLineEdit>
46
47 static QStringList Spacings;
48 static QRegExp Digits("(\\d)+");
49 static QRegExp DigitsMil("(\\d)+mil");
50
51 static const int MinSipPins = 1;
52 static const int MaxSipPins = 128;
53 static const int MinDipPins = 4;
54 static const int MaxDipPins = 128;
55
56 static HoleClassThing TheHoleThing;
57
58 // TODO
59 // save into parts bin
60
MysteryPart(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu,bool doLabel)61 MysteryPart::MysteryPart( ModelPart * modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu * itemMenu, bool doLabel)
62 : PaletteItem(modelPart, viewID, viewGeometry, id, itemMenu, doLabel)
63 {
64 m_chipLabel = modelPart->localProp("chip label").toString();
65 if (m_chipLabel.isEmpty()) {
66 m_chipLabel = modelPart->properties().value("chip label", "?");
67 modelPart->setLocalProp("chip label", m_chipLabel);
68 }
69
70 setUpHoleSizes("mystery", TheHoleThing);
71
72 }
73
~MysteryPart()74 MysteryPart::~MysteryPart() {
75 }
76
setProp(const QString & prop,const QString & value)77 void MysteryPart::setProp(const QString & prop, const QString & value) {
78 if (prop.compare("chip label", Qt::CaseInsensitive) == 0) {
79 setChipLabel(value, false);
80 return;
81 }
82
83 PaletteItem::setProp(prop, value);
84 }
85
setChipLabel(QString chipLabel,bool force)86 void MysteryPart::setChipLabel(QString chipLabel, bool force) {
87
88 if (!force && m_chipLabel.compare(chipLabel) == 0) return;
89
90 m_chipLabel = chipLabel;
91
92 QString svg;
93 switch (this->m_viewID) {
94 case ViewLayer::BreadboardView:
95 svg = makeSvg(chipLabel, true);
96 if (!svg.isEmpty()) {
97 resetRenderer(svg);
98 }
99 break;
100 case ViewLayer::SchematicView:
101 {
102 QTransform transform = untransform();
103 svg = makeSvg(chipLabel, false);
104 svg = retrieveSchematicSvg(svg);
105 resetLayerKin(svg);
106 retransform(transform);
107 }
108 break;
109 default:
110 break;
111 }
112
113 modelPart()->setLocalProp("chip label", chipLabel);
114
115 if (m_partLabel) m_partLabel->displayTextsIf();
116 }
117
retrieveSvg(ViewLayer::ViewLayerID viewLayerID,QHash<QString,QString> & svgHash,bool blackOnly,double dpi,double & factor)118 QString MysteryPart::retrieveSvg(ViewLayer::ViewLayerID viewLayerID, QHash<QString, QString> & svgHash, bool blackOnly, double dpi, double & factor)
119 {
120 QString svg = PaletteItem::retrieveSvg(viewLayerID, svgHash, blackOnly, dpi, factor);
121 switch (viewLayerID) {
122 case ViewLayer::Breadboard:
123 case ViewLayer::Icon:
124 return TextUtils::replaceTextElement(svg, "label", m_chipLabel);
125
126 case ViewLayer::Schematic:
127 svg = retrieveSchematicSvg(svg);
128 return TextUtils::removeSVGHeader(svg);
129
130 default:
131 break;
132 }
133
134 return svg;
135 }
136
retrieveSchematicSvg(QString & svg)137 QString MysteryPart::retrieveSchematicSvg(QString & svg) {
138
139 bool hasLocal = false;
140 QStringList labels = getPinLabels(hasLocal);
141
142 if (hasLocal) {
143 svg = makeSchematicSvg(labels, false);
144 }
145
146 return TextUtils::replaceTextElement(svg, "label", m_chipLabel);
147 }
148
149
makeSvg(const QString & chipLabel,bool replace)150 QString MysteryPart::makeSvg(const QString & chipLabel, bool replace) {
151 QString path = filename();
152 QFile file(filename());
153 QString svg;
154 if (file.open(QFile::ReadOnly)) {
155 svg = file.readAll();
156 file.close();
157 if (!replace) return svg;
158
159 return TextUtils::replaceTextElement(svg, "label", chipLabel);
160 }
161
162 return "";
163 }
164
collectValues(const QString & family,const QString & prop,QString & value)165 QStringList MysteryPart::collectValues(const QString & family, const QString & prop, QString & value) {
166 if (prop.compare("layout", Qt::CaseInsensitive) == 0) {
167 // TODO: translate these
168 QStringList values;
169 values << "Single Row" << "Double Row";
170 value = values.at(moduleID().contains("sip", Qt::CaseInsensitive) ? 0 : 1);
171 return values;
172 }
173
174 if (prop.compare("pin spacing", Qt::CaseInsensitive) == 0) {
175 QStringList values;
176 QString spacing;
177 TextUtils::getPinsAndSpacing(moduleID(), spacing);
178 if (isDIP()) {
179 foreach (QString f, spacings()) {
180 values.append(f);
181 }
182 }
183 else {
184 values.append(spacing);
185 }
186
187 value = spacing;
188 return values;
189 }
190
191 if (prop.compare("pins", Qt::CaseInsensitive) == 0) {
192 QStringList values;
193 value = modelPart()->properties().value("pins");
194
195 if (moduleID().contains("dip")) {
196 for (int i = MinDipPins; i <= MaxDipPins; i += 2) {
197 values << QString::number(i);
198 }
199 }
200 else {
201 for (int i = MinSipPins; i <= MaxSipPins; i++) {
202 values << QString::number(i);
203 }
204 }
205
206 return values;
207 }
208
209
210 return PaletteItem::collectValues(family, prop, value);
211 }
212
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)213 bool MysteryPart::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
214 {
215 if (prop.compare("chip label", Qt::CaseInsensitive) == 0) {
216 returnProp = tr("label");
217 returnValue = m_chipLabel;
218
219 QLineEdit * e1 = new QLineEdit(parent);
220 e1->setEnabled(swappingEnabled);
221 e1->setText(m_chipLabel);
222 connect(e1, SIGNAL(editingFinished()), this, SLOT(chipLabelEntry()));
223 e1->setObjectName("infoViewLineEdit");
224
225
226 returnWidget = e1;
227
228 return true;
229 }
230
231 if (prop.compare("hole size", Qt::CaseInsensitive) == 0) {
232 return collectHoleSizeInfo(TheHoleThing.holeSizeValue, parent, swappingEnabled, returnProp, returnValue, returnWidget);
233 }
234
235 return PaletteItem::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide);
236 }
237
getProperty(const QString & key)238 QString MysteryPart::getProperty(const QString & key) {
239 if (key.compare("chip label", Qt::CaseInsensitive) == 0) {
240 return m_chipLabel;
241 }
242
243 return PaletteItem::getProperty(key);
244 }
245
chipLabel()246 QString MysteryPart::chipLabel() {
247 return m_chipLabel;
248 }
249
addedToScene(bool temporary)250 void MysteryPart::addedToScene(bool temporary)
251 {
252 if (this->scene()) {
253 setChipLabel(m_chipLabel, true);
254 }
255
256 PaletteItem::addedToScene(temporary);
257 }
258
title()259 const QString & MysteryPart::title() {
260 return m_chipLabel;
261 }
262
hasCustomSVG()263 bool MysteryPart::hasCustomSVG() {
264 switch (m_viewID) {
265 case ViewLayer::BreadboardView:
266 case ViewLayer::SchematicView:
267 case ViewLayer::IconView:
268 case ViewLayer::PCBView:
269 return true;
270 default:
271 return ItemBase::hasCustomSVG();
272 }
273 }
274
chipLabelEntry()275 void MysteryPart::chipLabelEntry() {
276 QLineEdit * edit = qobject_cast<QLineEdit *>(sender());
277 if (edit == NULL) return;
278
279 if (edit->text().compare(this->chipLabel()) == 0) return;
280
281 InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
282 if (infoGraphicsView != NULL) {
283 infoGraphicsView->setProp(this, "chip label", tr("chip label"), this->chipLabel(), edit->text(), true);
284 }
285 }
286
isDIP()287 bool MysteryPart::isDIP() {
288 QString layout = modelPart()->properties().value("layout", "");
289 return (layout.indexOf("double", 0, Qt::CaseInsensitive) >= 0);
290 }
291
otherPropsChange(const QMap<QString,QString> & propsMap)292 bool MysteryPart::otherPropsChange(const QMap<QString, QString> & propsMap) {
293 QString layout = modelPart()->properties().value("layout", "");
294 return (layout.compare(propsMap.value("layout", "")) != 0);
295 }
296
spacings()297 const QStringList & MysteryPart::spacings() {
298 if (Spacings.count() == 0) {
299 Spacings << "100mil" << "200mil" << "300mil" << "400mil" << "500mil" << "600mil" << "700mil" << "800mil" << "900mil";
300 }
301 return Spacings;
302 }
303
isPlural()304 ItemBase::PluralType MysteryPart::isPlural() {
305 return Plural;
306 }
307
genSipFZP(const QString & moduleid)308 QString MysteryPart::genSipFZP(const QString & moduleid)
309 {
310 return genxFZP(moduleid, "mystery_part_sipFzpTemplate", MinSipPins, MaxSipPins, 1);
311 }
312
genDipFZP(const QString & moduleid)313 QString MysteryPart::genDipFZP(const QString & moduleid)
314 {
315 return genxFZP(moduleid, "mystery_part_dipFzpTemplate", MinDipPins, MaxDipPins, 2);
316
317 }
318
genxFZP(const QString & moduleid,const QString & templateName,int minPins,int maxPins,int step)319 QString MysteryPart::genxFZP(const QString & moduleid, const QString & templateName, int minPins, int maxPins, int step) {
320 QString spacingString;
321 TextUtils::getPinsAndSpacing(moduleid, spacingString);
322 QString result = PaletteItem::genFZP(moduleid, templateName, minPins, maxPins, step, false);
323 result.replace(".percent.", "%");
324 result = result.arg(spacingString);
325 return hackFzpHoleSize(result, moduleid);
326 }
327
hackFzpHoleSize(const QString & fzp,const QString & moduleid)328 QString MysteryPart::hackFzpHoleSize(const QString & fzp, const QString & moduleid) {
329 int hsix = moduleid.lastIndexOf(HoleSizePrefix);
330 if (hsix >= 0) {
331 return PaletteItem::hackFzpHoleSize(fzp, moduleid, hsix);
332 }
333
334 return fzp;
335 }
336
genModuleID(QMap<QString,QString> & currPropsMap)337 QString MysteryPart::genModuleID(QMap<QString, QString> & currPropsMap)
338 {
339 QString value = currPropsMap.value("layout");
340 bool single = value.contains("single", Qt::CaseInsensitive);
341 QString pins = currPropsMap.value("pins");
342 QString spacing = currPropsMap.value("pin spacing", "300mil");
343 if (single) {
344 return QString("mystery_part_sip_%1_100mil").arg(pins);
345 }
346 else {
347 int p = pins.toInt();
348 if (p < 4) p = 4;
349 if (p % 2 == 1) p--;
350 return QString("mystery_part_dip_%1_%2").arg(p).arg(spacing);
351 }
352 }
353
makeSchematicSvg(const QString & expectedFileName)354 QString MysteryPart::makeSchematicSvg(const QString & expectedFileName)
355 {
356 bool sip = expectedFileName.contains("sip", Qt::CaseInsensitive);
357
358 QStringList pieces = expectedFileName.split("_");
359
360 int pins = pieces.at(2).toInt();
361 QStringList labels;
362 for (int i = 0; i < pins; i++) {
363 labels << QString::number(i + 1);
364 }
365
366 if (expectedFileName.contains(PartFactory::OldSchematicPrefix)) {
367 return obsoleteMakeSchematicSvg(labels, sip);
368 }
369
370 return makeSchematicSvg(labels, sip);
371 }
372
makeSchematicSvg(const QStringList & labels,bool sip)373 QString MysteryPart::makeSchematicSvg(const QStringList & labels, bool sip)
374 {
375 QDomDocument fakeDoc;
376
377 QList<QDomElement> lefts;
378 for (int i = 0; i < labels.count(); i++) {
379 QDomElement element = fakeDoc.createElement("contact");
380 element.setAttribute("connectorIndex", i);
381 element.setAttribute("name", labels.at(i));
382 lefts.append(element);
383 }
384 QList<QDomElement> empty;
385 QStringList busNames;
386
387 QString titleText = sip ? "IC" : "?";
388 QString svg = SchematicRectConstants::genSchematicDIP(empty, empty, lefts, empty, empty, busNames, titleText, false, false, SchematicRectConstants::simpleGetConnectorName);
389 if (sip) return svg;
390
391 // add the mystery part graphic
392 QDomDocument doc;
393 if (!doc.setContent(svg)) return svg;
394
395 QRectF viewBox;
396 double w, h;
397 TextUtils::ensureViewBox(doc, GraphicsUtils::StandardFritzingDPI, viewBox, false, w, h, false);
398
399 double newUnit = 1000 * SchematicRectConstants::NewUnit / 25.4;
400 double rectStroke = 2 * 1000 * SchematicRectConstants::RectStrokeWidth / 25.4;
401 QString circle = QString("<circle cx='%1' cy='%2' r='%3' fill='black' stroke-width='0' stroke='none' />\n");
402 circle += QString("<text x='%1' fill='#FFFFFF' y='%4' font-family=\"%5\" text-anchor='middle' font-weight='bold' stroke='none' stroke-width='0' font-size='%6' >?</text>\n");
403 circle = circle
404 .arg(viewBox.width() - rectStroke - (newUnit / 2))
405 .arg(rectStroke + (newUnit / 2))
406 .arg(newUnit / 2)
407
408 .arg(rectStroke + (newUnit / 2) + (newUnit / 3)) // offset so the text appears in the center of the circle
409 .arg(SchematicRectConstants::FontFamily)
410 .arg(newUnit)
411 ;
412
413 QDomDocument temp;
414 temp.setContent(QString("<g>" + circle + "</g>"));
415
416 QDomElement root = doc.documentElement();
417 QDomElement schematic = TextUtils::findElementWithAttribute(root, "id", "schematic");
418 if (schematic.isNull()) return svg;
419
420 QDomElement tempRoot = temp.documentElement();
421 schematic.appendChild(tempRoot);
422
423 return doc.toString(1);
424 }
425
obsoleteMakeSchematicSvg(const QStringList & labels,bool sip)426 QString MysteryPart::obsoleteMakeSchematicSvg(const QStringList & labels, bool sip)
427 {
428 int increment = GraphicsUtils::StandardSchematicSeparationMils; // 7.5mm;
429 int border = 30;
430 double totalHeight = (labels.count() * increment) + increment + border;
431 int textOffset = 50;
432 int repeatTextOffset = 50;
433 int fontSize = 255;
434 int labelFontSize = 130;
435 int defaultLabelWidth = 30;
436 QString labelText = "?";
437 double textMax = defaultLabelWidth;
438 QFont font("Droid Sans", labelFontSize * 72 / GraphicsUtils::StandardFritzingDPI, QFont::Normal);
439 QFontMetricsF fm(font);
440 for (int i = 0; i < labels.count(); i++) {
441 double w = fm.width(labels.at(i));
442 if (w > textMax) textMax = w;
443 }
444 textMax = textMax * GraphicsUtils::StandardFritzingDPI / 72;
445
446 int totalWidth = (5 * increment) + border;
447 int innerWidth = 4 * increment;
448 if (textMax > defaultLabelWidth) {
449 totalWidth += (textMax - defaultLabelWidth);
450 innerWidth += (textMax - defaultLabelWidth);
451 }
452
453 QString header("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
454 "<svg xmlns:svg='http://www.w3.org/2000/svg' \n"
455 "xmlns='http://www.w3.org/2000/svg' \n"
456 "version='1.2' baseProfile='tiny' \n"
457 "width='%7in' height='%1in' viewBox='0 0 %8 %2'>\n"
458 "<g id='schematic'>\n"
459 "<rect x='315' y='15' fill='none' width='%9' height='%3' stroke='#000000' stroke-linejoin='round' stroke-linecap='round' stroke-width='30' />\n"
460 "<text id='label' x='%11' y='%4' fill='#000000' stroke='none' font-family='Droid Sans' text-anchor='middle' font-size='%5' >%6</text>\n");
461
462 if (!sip) {
463 header += "<circle fill='#000000' cx='%10' cy='200' r='150' stroke-width='0' />\n"
464 "<text x='%10' fill='#FFFFFF' y='305' font-family='Droid Sans' text-anchor='middle' font-weight='bold' stroke-width='0' font-size='275' >?</text>\n";
465 }
466 else {
467 labelText = "IC";
468 fontSize = 235;
469 textOffset = 0;
470 }
471
472 QString svg = header
473 .arg(totalHeight / GraphicsUtils::StandardFritzingDPI)
474 .arg(totalHeight)
475 .arg(totalHeight - border)
476 .arg((totalHeight / 2) + textOffset)
477 .arg(fontSize)
478 .arg(labelText)
479 .arg(totalWidth / 1000.0)
480 .arg(totalWidth)
481 .arg(innerWidth)
482 .arg(totalWidth - 200)
483 .arg(increment + textMax + ((totalWidth - increment - textMax) / 2.0))
484 ;
485
486
487 QString repeat("<line fill='none' stroke='#000000' stroke-linejoin='round' stroke-linecap='round' stroke-width='30' x1='15' y1='%1' x2='300' y2='%1' />\n"
488 "<rect x='0' y='%2' fill='none' width='300' height='30' id='connector%3pin' stroke-width='0' />\n"
489 "<rect x='0' y='%2' fill='none' width='30' height='30' id='connector%3terminal' stroke-width='0' />\n"
490 "<text id='label%3' x='390' y='%4' font-family='Droid Sans' stroke='none' fill='#000000' text-anchor='start' font-size='%6' >%5</text>\n");
491
492 for (int i = 0; i < labels.count(); i++) {
493 svg += repeat
494 .arg(increment + (border / 2) + (i * increment))
495 .arg(increment + (i * increment))
496 .arg(i)
497 .arg(increment + repeatTextOffset + (i * increment))
498 .arg(labels.at(i))
499 .arg(labelFontSize);
500 }
501
502 svg += "</g>\n";
503 svg += "</svg>\n";
504 return svg;
505 }
506
507
makeBreadboardSvg(const QString & expectedFileName)508 QString MysteryPart::makeBreadboardSvg(const QString & expectedFileName)
509 {
510 if (expectedFileName.contains("_sip_")) return makeBreadboardSipSvg(expectedFileName);
511 if (expectedFileName.contains("_dip_")) return makeBreadboardDipSvg(expectedFileName);
512
513 return "";
514 }
515
makeBreadboardDipSvg(const QString & expectedFileName)516 QString MysteryPart::makeBreadboardDipSvg(const QString & expectedFileName)
517 {
518 QString spacingString;
519 int pins = TextUtils::getPinsAndSpacing(expectedFileName, spacingString);
520 double spacing = TextUtils::convertToInches(spacingString) * 100;
521
522 int increment = 10;
523
524 QString repeatT("<rect id='connector%1terminal' x='[1.87]' y='1' fill='#8C8C8C' stroke='none' stroke-width='0' width='2.3' height='0'/>\n"
525 "<rect id='connector%1pin' x='[1.87]' y='0' fill='#8C8C8C' stroke='none' stroke-width='0' width='2.3' height='3.5'/>\n");
526
527 QString repeatB("<rect id='connector%1terminal' x='{1.87}' y='[11.0]' fill='#8C8C8C' stroke='none' stroke-width='0' width='2.3' height='0'/>\n"
528 "<rect id='connector%1pin' x='{1.87}' y='[7.75]' fill='#8C8C8C' stroke='none' stroke-width='0' width='2.3' height='4.25'/>\n");
529
530 QString header("<?xml version='1.0' encoding='utf-8'?>\n"
531 "<svg version='1.2' baseProfile='tiny' xmlns='http://www.w3.org/2000/svg' \n"
532 "width='.percent.1in' height='%1in' viewBox='0 0 {16.0022} [12.0]'>\n"
533 "<g id='breadboard'>\n"
534 ".percent.2\n"
535 "<rect width='{16.0022}' x='0' y='2.5' height='[6.5]' fill='#000000' id='upper' stroke-width='0' />\n"
536 "<rect width='{16.0022}' x='0' y='[6.5]' fill='#404040' height='3.096' id='lower' stroke-width='0' />\n"
537 "<text id='label' x='2.5894' y='{{6.0}}' fill='#e6e6e6' stroke='none' font-family='Droid Sans' text-anchor='start' font-size='7.3' >?</text>\n"
538 "<circle fill='#8C8C8C' cx='11.0022' cy='{{7.5}}' r='3' stroke-width='0' />\n"
539 "<text x='11.0022' y='{{9.2}}' font-family='Droid Sans' text-anchor='middle' font-weight='bold' stroke-width='0' font-size='5.5' >?</text>\n"
540 ".percent.3\n"
541 "</g>\n"
542 "</svg>\n");
543
544
545 header = TextUtils::incrementTemplateString(header, 1, spacing - increment, TextUtils::incMultiplyPinFunction, TextUtils::noCopyPinFunction, NULL);
546 header = header.arg(TextUtils::getViewBoxCoord(header, 3) / 100.0);
547 if (spacing == 10) {
548 header.replace("{{6.0}}", "8.0");
549 header.replace("{{7.5}}", "5.5");
550 header.replace("{{9.2}}", "7.2");
551 }
552 else {
553 header.replace("{{6.0}}", QString::number(6.0 + ((spacing - increment) / 2)));
554 header.replace("{{7.5}}", "7.5");
555 header.replace("{{9.2}}", "9.2");
556 }
557 header.replace(".percent.", "%");
558 header.replace("{", "[");
559 header.replace("}", "]");
560
561 QString svg = TextUtils::incrementTemplateString(header, 1, increment * ((pins - 4) / 2), TextUtils::incMultiplyPinFunction, TextUtils::noCopyPinFunction, NULL);
562
563 repeatB = TextUtils::incrementTemplateString(repeatB, 1, spacing - increment, TextUtils::incMultiplyPinFunction, TextUtils::noCopyPinFunction, NULL);
564 repeatB.replace("{", "[");
565 repeatB.replace("}", "]");
566
567 int userData[2];
568 userData[0] = pins;
569 userData[1] = 1;
570 QString repeatTs = TextUtils::incrementTemplateString(repeatT, pins / 2, increment, TextUtils::standardMultiplyPinFunction, TextUtils::negIncCopyPinFunction, userData);
571 QString repeatBs = TextUtils::incrementTemplateString(repeatB, pins / 2, increment, TextUtils::standardMultiplyPinFunction, TextUtils::standardCopyPinFunction, NULL);
572
573 return svg.arg(TextUtils::getViewBoxCoord(svg, 2) / 100).arg(repeatTs).arg(repeatBs);
574 }
575
makeBreadboardSipSvg(const QString & expectedFileName)576 QString MysteryPart::makeBreadboardSipSvg(const QString & expectedFileName)
577 {
578 QStringList pieces = expectedFileName.split("_");
579 if (pieces.count() != 6) return "";
580
581 int pins = pieces.at(2).toInt();
582 int increment = 10;
583
584 QString header("<?xml version='1.0' encoding='utf-8'?>\n"
585 "<svg version='1.2' baseProfile='tiny' id='svg2' xmlns='http://www.w3.org/2000/svg' \n"
586 "width='%1in' height='0.27586in' viewBox='0 0 [6.0022] 27.586'>\n"
587 "<g id='breadboard'>\n"
588 "<rect width='[6.0022]' x='0' y='0' height='24.17675' fill='#000000' id='upper' stroke-width='0' />\n"
589 "<rect width='[6.0022]' x='0' y='22' fill='#404040' height='3.096' id='lower' stroke-width='0' />\n"
590 "<text id='label' x='2.5894' y='13' fill='#e6e6e6' stroke='none' font-family='Droid Sans' text-anchor='start' font-size='7.3' >?</text>\n"
591 "<circle fill='#8C8C8C' cx='[1.0022]' cy='5' r='3' stroke-width='0' />\n"
592 "<text x='[1.0022]' y='6.7' font-family='Droid Sans' text-anchor='middle' font-weight='bold' stroke-width='0' font-size='5.5' >?</text>\n"
593 "%2\n"
594 "</g>\n"
595 "</svg>\n");
596
597 QString svg = TextUtils::incrementTemplateString(header, 1, increment * (pins - 1), TextUtils::incMultiplyPinFunction, TextUtils::noCopyPinFunction, NULL);
598
599 QString repeat("<rect id='connector%1terminal' stroke='none' stroke-width='0' x='[1.87]' y='25.586' fill='#8C8C8C' width='2.3' height='2.0'/>\n"
600 "<rect id='connector%1pin' stroke='none' stroke-width='0' x='[1.87]' y='23.336' fill='#8C8C8C' width='2.3' height='4.25'/>\n");
601
602 QString repeats = TextUtils::incrementTemplateString(repeat, pins, increment, TextUtils::standardMultiplyPinFunction, TextUtils::standardCopyPinFunction, NULL);
603
604 return svg.arg(TextUtils::getViewBoxCoord(svg, 2) / 100).arg(repeats);
605 }
606
changePinLabels(bool singleRow,bool sip)607 bool MysteryPart::changePinLabels(bool singleRow, bool sip) {
608 Q_UNUSED(singleRow);
609
610 if (m_viewID != ViewLayer::SchematicView) return true;
611
612 bool hasLocal = false;
613 QStringList labels = getPinLabels(hasLocal);
614 if (labels.count() == 0) return true;
615
616 QTransform transform = untransform();
617
618 QString svg = MysteryPart::makeSchematicSvg(labels, sip);
619
620 QString chipLabel = modelPart()->localProp("chip label").toString();
621 if (!chipLabel.isEmpty()) {
622 svg =TextUtils::replaceTextElement(svg, "label", chipLabel);
623 }
624
625 resetLayerKin(svg);
626
627 retransform(transform);
628
629 return true;
630 }
631
swapEntry(const QString & text)632 void MysteryPart::swapEntry(const QString & text) {
633
634 FamilyPropertyComboBox * comboBox = qobject_cast<FamilyPropertyComboBox *>(sender());
635 if (comboBox == NULL) return;
636
637 QString layout = m_propsMap.value("layout");
638
639 if (comboBox->prop().contains("layout", Qt::CaseInsensitive)) {
640 layout = text;
641 }
642
643 if (layout.isEmpty()) {
644 if (moduleID().contains("sip", Qt::CaseInsensitive)) {
645 layout = "single";
646 }
647 }
648
649 if (layout.contains("single", Qt::CaseInsensitive)) {
650 generateSwap(text, genModuleID, genSipFZP, makeBreadboardSvg, makeSchematicSvg, PinHeader::makePcbSvg);
651 }
652 else {
653 generateSwap(text, genModuleID, genDipFZP, makeBreadboardSvg, makeSchematicSvg, makePcbDipSvg);
654 }
655 PaletteItem::swapEntry(text);
656 }
657
makePcbDipSvg(const QString & expectedFileName)658 QString MysteryPart::makePcbDipSvg(const QString & expectedFileName)
659 {
660 QString spacingString;
661 int pins = TextUtils::getPinsAndSpacing(expectedFileName, spacingString);
662 if (pins == 0) return "";
663
664 QString header("<?xml version='1.0' encoding='UTF-8'?>\n"
665 "<svg baseProfile='tiny' version='1.2' width='%1in' height='%2in' viewBox='0 0 %3 %4' xmlns='http://www.w3.org/2000/svg'>\n"
666 "<desc>Fritzing footprint SVG</desc>\n"
667 "<g id='silkscreen'>\n"
668 "<line stroke='white' stroke-width='10' x1='10' x2='10' y1='10' y2='%5'/>\n"
669 "<line stroke='white' stroke-width='10' x1='10' x2='%6' y1='%5' y2='%5'/>\n"
670 "<line stroke='white' stroke-width='10' x1='%6' x2='%6' y1='%5' y2='10'/>\n"
671 "<line stroke='white' stroke-width='10' x1='10' x2='%7' y1='10' y2='10'/>\n"
672 "<line stroke='white' stroke-width='10' x1='%8' x2='%6' y1='10' y2='10'/>\n"
673 "</g>\n"
674 "<g id='copper1'><g id='copper0'>\n"
675 "<rect id='square' fill='none' height='55' stroke='rgb(255, 191, 0)' stroke-width='20' width='55' x='32.5' y='32.5'/>\n");
676
677 double outerBorder = 10;
678 double silkSplitTop = 100;
679 double offsetX = 60;
680 double offsetY = 60;
681 double spacing = TextUtils::convertToInches(spacingString) * GraphicsUtils::StandardFritzingDPI;
682 double totalWidth = 120 + spacing;
683 double totalHeight = (100 * pins / 2) + (outerBorder * 2);
684 double center = totalWidth / 2;
685
686 QString svg = header.arg(totalWidth / GraphicsUtils::StandardFritzingDPI).arg(totalHeight / GraphicsUtils::StandardFritzingDPI).arg(totalWidth).arg(totalHeight)
687 .arg(totalHeight - outerBorder).arg(totalWidth - outerBorder)
688 .arg(center - (silkSplitTop / 2)).arg(center + (silkSplitTop / 2));
689
690 QString circle("<circle cx='%1' cy='%2' fill='none' id='connector%3pin' r='27.5' stroke='rgb(255, 191, 0)' stroke-width='20'/>\n");
691
692 int y = offsetY;
693 for (int i = 0; i < pins / 2; i++) {
694 svg += circle.arg(offsetX).arg(y).arg(i);
695 svg += circle.arg(totalWidth - offsetX).arg(y).arg(pins - 1 - i);
696 y += 100;
697 }
698
699 svg += "</g></g>\n";
700 svg += "</svg>\n";
701
702 int hsix = expectedFileName.indexOf(HoleSizePrefix);
703 if (hsix >= 0) {
704 return hackSvgHoleSizeAux(svg, expectedFileName);
705 }
706
707 return svg;
708 }
709