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: 6984 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-04-22 23:44:56 +0200 (Mo, 22. Apr 2013) $
24 
25 ********************************************************************/
26 
27 #include "hole.h"
28 #include "../utils/graphicsutils.h"
29 #include "../fsvgrenderer.h"
30 #include "../sketch/infographicsview.h"
31 #include "../svg/svgfilesplitter.h"
32 #include "../commands.h"
33 #include "../utils/textutils.h"
34 #include "../viewlayer.h"
35 #include "partlabel.h"
36 #include "../connectors/nonconnectoritem.h"
37 #include "../connectors/svgidlayer.h"
38 
39 #include <QDomNodeList>
40 #include <QDomDocument>
41 #include <QDomElement>
42 #include <QLineEdit>
43 #include <QVBoxLayout>
44 #include <QGridLayout>
45 #include <QLabel>
46 #include <QSpacerItem>
47 #include <QGroupBox>
48 #include <QSettings>
49 
50 const double Hole::OffsetPixels = 2;
51 
52 static HoleClassThing TheHoleThing;
53 
54 //////////////////////////////////////////////////
55 
Hole(ModelPart * modelPart,ViewLayer::ViewID viewID,const ViewGeometry & viewGeometry,long id,QMenu * itemMenu,bool doLabel)56 Hole::Hole( ModelPart * modelPart, ViewLayer::ViewID viewID, const ViewGeometry & viewGeometry, long id, QMenu * itemMenu, bool doLabel)
57 	: PaletteItem(modelPart, viewID, viewGeometry, id, itemMenu, doLabel)
58 {
59 	PaletteItem::setUpHoleSizes("hole", TheHoleThing);
60 }
61 
~Hole()62 Hole::~Hole() {
63 }
64 
setProp(const QString & prop,const QString & value)65 void Hole::setProp(const QString & prop, const QString & value) {
66 	if (prop.compare("hole size", Qt::CaseInsensitive) == 0) {
67 		setHoleSize(value, false);
68 		return;
69 	}
70 
71 	PaletteItem::setProp(prop, value);
72 }
73 
holeSize()74 QString Hole::holeSize() {
75 	return m_holeSettings.holeSize();
76 }
77 
78 
setHoleSize(QString newSize,bool force)79 void Hole::setHoleSize(QString newSize, bool force) {
80 	//DebugDialog::debug(QString("old holesize %1").arg(viewID()) + holeSize(), sceneBoundingRect());
81 	//foreach (QGraphicsItem * childItem, childItems()) {
82 	//	DebugDialog::debug(QString("   child"), childItem->sceneBoundingRect());
83 	//}
84 
85 	if (PaletteItem::setHoleSize(newSize, force, m_holeSettings)) {
86 		setBoth(m_holeSettings.holeDiameter, m_holeSettings.ringThickness);
87 		modelPart()->setLocalProp("hole size", newSize);
88 
89 		if (m_partLabel) m_partLabel->displayTextsIf();
90 	}
91 	//DebugDialog::debug(QString("new holesize %1 ").arg(viewID()) + holeSize(), sceneBoundingRect());
92 	//foreach (QGraphicsItem * childItem, childItems()) {
93 	//	DebugDialog::debug(QString("   child"), childItem->sceneBoundingRect());
94 	//}
95 }
96 
getRect(const QString & newSize)97 QRectF Hole::getRect(const QString & newSize) {
98 	QString s = newSize;
99 	QStringList sizes = getSizes(s, m_holeSettings);
100 	if (sizes.count() < 2) return boundingRect();
101 
102 	double diameter = TextUtils::convertToInches(sizes.at(0));
103 	double ringThickness = TextUtils::convertToInches(sizes.at(1));
104 	double dim = (diameter + ringThickness + ringThickness) * GraphicsUtils::SVGDPI;
105 	//DebugDialog::debug(QString("get rect %1 %2").arg(newSize).arg(dim));
106 	return QRectF(0, 0, dim, dim);
107 }
108 
setBoth(const QString & holeDiameter,const QString & ringThickness)109 void Hole::setBoth(const QString & holeDiameter, const QString & ringThickness) {
110 	if (this->m_viewID != ViewLayer::PCBView) return;
111 
112 	ItemBase * otherLayer = setBothSvg(holeDiameter, ringThickness);
113 
114 	// there's only one NonConnectorItem
115 	foreach (SvgIdLayer * svgIdLayer, fsvgRenderer()->setUpNonConnectors(viewLayerPlacement())) {
116 		if (svgIdLayer == NULL) continue;
117 
118 		setBothNonConnectors(this, svgIdLayer);
119 		if (otherLayer != NULL) {
120 			setBothNonConnectors(otherLayer, svgIdLayer);
121 		}
122 
123 		delete svgIdLayer;
124 	}
125 }
126 
setBothSvg(const QString & holeDiameter,const QString & ringThickness)127 ItemBase * Hole::setBothSvg(const QString & holeDiameter, const QString & ringThickness)
128 {
129 	QString svg = makeSvg(holeDiameter, ringThickness, m_viewLayerID, true);
130 	resetRenderer(svg);
131 	//DebugDialog::debug("both");
132 	//DebugDialog::debug(svg);
133 
134 	QString setColor;
135 	QStringList noIDs;
136 
137 	QString osvg;
138 	ItemBase * otherLayer = NULL;
139 	foreach (ItemBase * layerKin, m_layerKin) {
140 		if (layerKin->hasNonConnectors()) {
141 			otherLayer = layerKin;
142 			break;
143 		}
144 	}
145 
146 	if (otherLayer) {
147 		osvg = makeSvg(holeDiameter, ringThickness, otherLayer->viewLayerID(), true);
148 		//DebugDialog::debug(osvg);
149 		otherLayer->resetRenderer(osvg);
150 	}
151 
152 	//DebugDialog::debug("other");
153 
154 	return otherLayer;
155 }
156 
setBothNonConnectors(ItemBase * itemBase,SvgIdLayer * svgIdLayer)157 void Hole::setBothNonConnectors(ItemBase * itemBase, SvgIdLayer * svgIdLayer) {
158 	foreach (QGraphicsItem * child, itemBase->childItems()) {
159 		NonConnectorItem * nonConnectorItem = dynamic_cast<NonConnectorItem *>(child);
160 		if (nonConnectorItem == NULL) continue;
161 
162 		//DebugDialog::debug(QString("hole set rect %1").arg(m_viewID), svgIdLayer->m_rect);
163 		nonConnectorItem->setRect(svgIdLayer->rect(viewLayerPlacement()));
164 		nonConnectorItem->setRadius(svgIdLayer->m_radius, svgIdLayer->m_strokeWidth);
165 		break;
166 	}
167 }
168 
169 
makeSvg(const QString & holeDiameter,const QString & ringThickness,ViewLayer::ViewLayerID viewLayerID,bool includeHole)170 QString Hole::makeSvg(const QString & holeDiameter, const QString & ringThickness, ViewLayer::ViewLayerID viewLayerID, bool includeHole)
171 {
172 	double offsetDPI = OffsetPixels / GraphicsUtils::SVGDPI;
173 	double hd = TextUtils::convertToInches(holeDiameter);
174 	double rt = TextUtils::convertToInches(ringThickness);
175 
176 	double wInches = hd + rt + rt + offsetDPI + offsetDPI;
177 	QString svg = TextUtils::makeSVGHeader(1, GraphicsUtils::StandardFritzingDPI, wInches, wInches);
178 
179 	hd *= GraphicsUtils::StandardFritzingDPI;
180 	rt *= GraphicsUtils::StandardFritzingDPI;
181 	offsetDPI *= GraphicsUtils::StandardFritzingDPI;
182 
183 	QString setColor;
184 	if (viewLayerID == ViewLayer::Copper0) {
185 		setColor = ViewLayer::Copper0Color;
186 	}
187 	else if (viewLayerID == ViewLayer::Copper1) {
188 		setColor = ViewLayer::Copper1Color;
189 	}
190 
191 	svg += QString("<g id='%1'>").arg(ViewLayer::viewLayerXmlNameFromID(viewLayerID));
192 
193 	QString id = makeID();
194 	if (hd == 0) {
195 		svg += QString("<circle cx='%1' cy='%1' r='%2' fill='%3' id='%4' />")
196 					.arg(rt + offsetDPI)
197 					.arg(rt)
198 					.arg(setColor)
199 					.arg(id);
200 	}
201 	else {
202 		svg += QString("<circle fill='%6' cx='%1' cy='%1' r='%2' stroke-width='%3' stroke='%4' id='%5' />")
203 			.arg((hd / 2) + rt + offsetDPI)
204 			.arg((hd / 2) + (rt / 2))
205 			.arg(rt)
206 			.arg(setColor)
207 			.arg(id)
208             .arg(rt == 0 ? "black" : "none")
209             ;
210         if (includeHole) {
211 		    svg += QString("<circle drill='0' fill='black' cx='%1' cy='%1' r='%2' stroke-width='0'  />")   // set the drill attribute to 0 for gerber translation
212 			    .arg((hd / 2) + rt + offsetDPI)
213 			    .arg(hd / 2);
214         }
215 	}
216 
217 	svg += "</g></svg>";
218 	//DebugDialog::debug("hole svg " + svg);
219 	return svg;
220 }
221 
makeID()222 QString Hole::makeID() {
223 	return FSvgRenderer::NonConnectorName + "0";
224 }
225 
getProperty(const QString & key)226 QString Hole::getProperty(const QString & key) {
227 	if (key.compare("hole size", Qt::CaseInsensitive) == 0) {
228 		return m_holeSettings.holeDiameter;
229 	}
230 
231 	return PaletteItem::getProperty(key);
232 }
233 
addedToScene(bool temporary)234 void Hole::addedToScene(bool temporary)
235 {
236 	if (this->scene()) {
237 		setHoleSize(m_holeSettings.holeSize(), true);
238 	}
239 
240     return PaletteItem::addedToScene(temporary);
241 }
242 
hasCustomSVG()243 bool Hole::hasCustomSVG() {
244 	switch (m_viewID) {
245 		case ViewLayer::PCBView:
246 			return true;
247 		default:
248 			return ItemBase::hasCustomSVG();
249 	}
250 }
251 
isPlural()252 ItemBase::PluralType Hole::isPlural() {
253 	return Plural;
254 }
255 
retrieveSvg(ViewLayer::ViewLayerID viewLayerID,QHash<QString,QString> & svgHash,bool blackOnly,double dpi,double & factor)256 QString Hole::retrieveSvg(ViewLayer::ViewLayerID viewLayerID, QHash<QString, QString> & svgHash, bool blackOnly, double dpi, double & factor)
257 {
258 	if (m_viewID != ViewLayer::PCBView ||
259 		(viewLayerID != ViewLayer::Copper0 && viewLayerID != ViewLayer::Copper1))
260 	{
261 		return PaletteItemBase::retrieveSvg(viewLayerID, svgHash, blackOnly, dpi, factor);
262 	}
263 
264 	QStringList holeSize = m_modelPart->localProp("hole size").toString().split(",");
265 	if (holeSize.length() == 2) {
266 		QString svg = makeSvg(holeSize.at(0), holeSize.at(1), viewLayerID, false);
267 		if (!svg.isEmpty()) {
268             return PaletteItemBase::normalizeSvg(svg, viewLayerID, blackOnly, dpi, factor);
269 		}
270 	}
271 
272 	return PaletteItemBase::retrieveSvg(viewLayerID, svgHash, blackOnly, dpi, factor);
273 }
274 
collectExtraInfo(QWidget * parent,const QString & family,const QString & prop,const QString & value,bool swappingEnabled,QString & returnProp,QString & returnValue,QWidget * & returnWidget,bool & hide)275 bool Hole::collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide)
276 {
277 	if (prop.compare("hole size", Qt::CaseInsensitive) == 0) {
278         return collectHoleSizeInfo(TheHoleThing.holeSizeValue, parent, swappingEnabled, returnProp, returnValue, returnWidget);
279 	}
280 
281 	return PaletteItem::collectExtraInfo(parent, family, prop, value, swappingEnabled, returnProp, returnValue, returnWidget, hide);
282 }
283 
changeHoleSize(const QString & newSize)284 void Hole::changeHoleSize(const QString & newSize) {
285 	InfoGraphicsView * infoGraphicsView = InfoGraphicsView::getInfoGraphicsView(this);
286 	if (infoGraphicsView != NULL) {
287         QRectF holeRect = getRect(holeSize());
288         QRectF newHoleRect = getRect(newSize);
289         infoGraphicsView->setHoleSize(this, "hole size", tr("hole size"), holeSize(), newSize, holeRect, newHoleRect, true);
290 	}
291 }
292 
canEditPart()293 bool Hole::canEditPart() {
294 	return false;
295 }
296 
hasPartNumberProperty()297 bool Hole::hasPartNumberProperty()
298 {
299 	return false;
300 }
301 
rotationAllowed()302 bool Hole::rotationAllowed() {
303 	return false;
304 }
305 
rotation45Allowed()306 bool Hole::rotation45Allowed() {
307 	return false;
308 }
309 
canFindConnectorsUnder()310 bool Hole::canFindConnectorsUnder() {
311 	return false;
312 }
313 
useViewIDForPixmap(ViewLayer::ViewID vid,bool)314 ViewLayer::ViewID Hole::useViewIDForPixmap(ViewLayer::ViewID vid, bool)
315 {
316     if (vid == ViewLayer::PCBView) {
317         return ViewLayer::IconView;
318     }
319 
320     return ViewLayer::UnknownView;
321 }
322 
changeUnits(bool)323 void Hole::changeUnits(bool)
324 {
325 	QString newVal = PaletteItem::changeUnits(m_holeSettings);
326 	modelPart()->setLocalProp("hole size", newVal);
327 }
328 
trueSceneBoundingRect()329 QRectF Hole::trueSceneBoundingRect() {
330     QRectF r = sceneBoundingRect();
331     return r.adjusted(OffsetPixels, OffsetPixels, -OffsetPixels, -OffsetPixels);
332 }
333 
334 
335