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