1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program 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  * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*******************************************************************************
21  *  Includes
22  ******************************************************************************/
23 #include "footprint.h"
24 
25 #include "footprintgraphicsitem.h"
26 #include "package.h"
27 
28 #include <QtCore>
29 
30 /*******************************************************************************
31  *  Namespace
32  ******************************************************************************/
33 namespace librepcb {
34 namespace library {
35 
36 /*******************************************************************************
37  *  Constructors / Destructor
38  ******************************************************************************/
39 
Footprint(const Footprint & other)40 Footprint::Footprint(const Footprint& other) noexcept
41   : onEdited(*this),
42     mUuid(other.mUuid),
43     mNames(other.mNames),
44     mDescriptions(other.mDescriptions),
45     mPads(other.mPads),
46     mPolygons(other.mPolygons),
47     mCircles(other.mCircles),
48     mStrokeTexts(other.mStrokeTexts),
49     mHoles(other.mHoles),
50     mStrokeFont(nullptr),
51     mRegisteredGraphicsItem(nullptr),
52     mNamesEditedSlot(*this, &Footprint::namesEdited),
53     mDescriptionsEditedSlot(*this, &Footprint::descriptionsEdited),
54     mPadsEditedSlot(*this, &Footprint::padsEdited),
55     mPolygonsEditedSlot(*this, &Footprint::polygonsEdited),
56     mCirclesEditedSlot(*this, &Footprint::circlesEdited),
57     mStrokeTextsEditedSlot(*this, &Footprint::strokeTextsEdited),
58     mHolesEditedSlot(*this, &Footprint::holesEdited) {
59   mNames.onEdited.attach(mNamesEditedSlot);
60   mDescriptions.onEdited.attach(mDescriptionsEditedSlot);
61   mPads.onEdited.attach(mPadsEditedSlot);
62   mPolygons.onEdited.attach(mPolygonsEditedSlot);
63   mCircles.onEdited.attach(mCirclesEditedSlot);
64   mStrokeTexts.onEdited.attach(mStrokeTextsEditedSlot);
65   mHoles.onEdited.attach(mHolesEditedSlot);
66 }
67 
Footprint(const Uuid & uuid,const ElementName & name_en_US,const QString & description_en_US)68 Footprint::Footprint(const Uuid& uuid, const ElementName& name_en_US,
69                      const QString& description_en_US)
70   : onEdited(*this),
71     mUuid(uuid),
72     mNames(name_en_US),
73     mDescriptions(description_en_US),
74     mPads(),
75     mPolygons(),
76     mCircles(),
77     mStrokeTexts(),
78     mHoles(),
79     mStrokeFont(nullptr),
80     mRegisteredGraphicsItem(nullptr),
81     mNamesEditedSlot(*this, &Footprint::namesEdited),
82     mDescriptionsEditedSlot(*this, &Footprint::descriptionsEdited),
83     mPadsEditedSlot(*this, &Footprint::padsEdited),
84     mPolygonsEditedSlot(*this, &Footprint::polygonsEdited),
85     mCirclesEditedSlot(*this, &Footprint::circlesEdited),
86     mStrokeTextsEditedSlot(*this, &Footprint::strokeTextsEdited),
87     mHolesEditedSlot(*this, &Footprint::holesEdited) {
88   mNames.onEdited.attach(mNamesEditedSlot);
89   mDescriptions.onEdited.attach(mDescriptionsEditedSlot);
90   mPads.onEdited.attach(mPadsEditedSlot);
91   mPolygons.onEdited.attach(mPolygonsEditedSlot);
92   mCircles.onEdited.attach(mCirclesEditedSlot);
93   mStrokeTexts.onEdited.attach(mStrokeTextsEditedSlot);
94   mHoles.onEdited.attach(mHolesEditedSlot);
95 }
96 
Footprint(const SExpression & node,const Version & fileFormat)97 Footprint::Footprint(const SExpression& node, const Version& fileFormat)
98   : onEdited(*this),
99     mUuid(deserialize<Uuid>(node.getChild("@0"), fileFormat)),
100     mNames(node, fileFormat),
101     mDescriptions(node, fileFormat),
102     mPads(node, fileFormat),
103     mPolygons(node, fileFormat),
104     mCircles(node, fileFormat),
105     mStrokeTexts(node, fileFormat),
106     mHoles(node, fileFormat),
107     mStrokeFont(nullptr),
108     mRegisteredGraphicsItem(nullptr),
109     mNamesEditedSlot(*this, &Footprint::namesEdited),
110     mDescriptionsEditedSlot(*this, &Footprint::descriptionsEdited),
111     mPadsEditedSlot(*this, &Footprint::padsEdited),
112     mPolygonsEditedSlot(*this, &Footprint::polygonsEdited),
113     mCirclesEditedSlot(*this, &Footprint::circlesEdited),
114     mStrokeTextsEditedSlot(*this, &Footprint::strokeTextsEdited),
115     mHolesEditedSlot(*this, &Footprint::holesEdited) {
116   mNames.onEdited.attach(mNamesEditedSlot);
117   mDescriptions.onEdited.attach(mDescriptionsEditedSlot);
118   mPads.onEdited.attach(mPadsEditedSlot);
119   mPolygons.onEdited.attach(mPolygonsEditedSlot);
120   mCircles.onEdited.attach(mCirclesEditedSlot);
121   mStrokeTexts.onEdited.attach(mStrokeTextsEditedSlot);
122   mHoles.onEdited.attach(mHolesEditedSlot);
123 }
124 
~Footprint()125 Footprint::~Footprint() noexcept {
126   Q_ASSERT(mRegisteredGraphicsItem == nullptr);
127 }
128 
129 /*******************************************************************************
130  *  General Methods
131  ******************************************************************************/
132 
setStrokeFontForAllTexts(const StrokeFont * font)133 void Footprint::setStrokeFontForAllTexts(const StrokeFont* font) noexcept {
134   mStrokeFont = font;
135   for (StrokeText& text : mStrokeTexts) {
136     text.setFont(mStrokeFont);
137   }
138 }
139 
registerGraphicsItem(FootprintGraphicsItem & item)140 void Footprint::registerGraphicsItem(FootprintGraphicsItem& item) noexcept {
141   Q_ASSERT(!mRegisteredGraphicsItem);
142   mRegisteredGraphicsItem = &item;
143 }
144 
unregisterGraphicsItem(FootprintGraphicsItem & item)145 void Footprint::unregisterGraphicsItem(FootprintGraphicsItem& item) noexcept {
146   Q_ASSERT(mRegisteredGraphicsItem == &item);
147   mRegisteredGraphicsItem = nullptr;
148 }
149 
serialize(SExpression & root) const150 void Footprint::serialize(SExpression& root) const {
151   root.appendChild(mUuid);
152   mNames.serialize(root);
153   mDescriptions.serialize(root);
154   mPads.serialize(root);
155   mPolygons.serialize(root);
156   mCircles.serialize(root);
157   mStrokeTexts.serialize(root);
158   mHoles.serialize(root);
159 }
160 
161 /*******************************************************************************
162  *  Operator Overloadings
163  ******************************************************************************/
164 
operator ==(const Footprint & rhs) const165 bool Footprint::operator==(const Footprint& rhs) const noexcept {
166   if (mUuid != rhs.mUuid) return false;
167   if (mNames != rhs.mNames) return false;
168   if (mDescriptions != rhs.mDescriptions) return false;
169   if (mPads != rhs.mPads) return false;
170   if (mPolygons != rhs.mPolygons) return false;
171   if (mCircles != rhs.mCircles) return false;
172   if (mStrokeTexts != rhs.mStrokeTexts) return false;
173   if (mHoles != rhs.mHoles) return false;
174   return true;
175 }
176 
operator =(const Footprint & rhs)177 Footprint& Footprint::operator=(const Footprint& rhs) noexcept {
178   if (mUuid != rhs.mUuid) {
179     mUuid = rhs.mUuid;
180     onEdited.notify(Event::UuidChanged);
181   }
182   mNames = rhs.mNames;
183   mDescriptions = rhs.mDescriptions;
184   mPads = rhs.mPads;
185   mPolygons = rhs.mPolygons;
186   mCircles = rhs.mCircles;
187   mStrokeTexts = rhs.mStrokeTexts;
188   mHoles = rhs.mHoles;
189   return *this;
190 }
191 
192 /*******************************************************************************
193  *  Private Methods
194  ******************************************************************************/
195 
namesEdited(const LocalizedNameMap & names,const QString & key,LocalizedNameMap::Event event)196 void Footprint::namesEdited(const LocalizedNameMap& names, const QString& key,
197                             LocalizedNameMap::Event event) noexcept {
198   Q_UNUSED(names);
199   Q_UNUSED(key);
200   Q_UNUSED(event);
201   onEdited.notify(Event::NamesEdited);
202 }
203 
descriptionsEdited(const LocalizedDescriptionMap & names,const QString & key,LocalizedDescriptionMap::Event event)204 void Footprint::descriptionsEdited(
205     const LocalizedDescriptionMap& names, const QString& key,
206     LocalizedDescriptionMap::Event event) noexcept {
207   Q_UNUSED(names);
208   Q_UNUSED(key);
209   Q_UNUSED(event);
210   onEdited.notify(Event::DescriptionsEdited);
211 }
212 
padsEdited(const FootprintPadList & list,int index,const std::shared_ptr<const FootprintPad> & pad,FootprintPadList::Event event)213 void Footprint::padsEdited(const FootprintPadList& list, int index,
214                            const std::shared_ptr<const FootprintPad>& pad,
215                            FootprintPadList::Event event) noexcept {
216   Q_UNUSED(list);
217   Q_UNUSED(index);
218   switch (event) {
219     case FootprintPadList::Event::ElementAdded:
220       if (mRegisteredGraphicsItem) {
221         mRegisteredGraphicsItem->addPad(const_cast<FootprintPad&>(*pad));
222       }
223       break;
224     case FootprintPadList::Event::ElementRemoved:
225       if (mRegisteredGraphicsItem) {
226         mRegisteredGraphicsItem->removePad(const_cast<FootprintPad&>(*pad));
227       }
228       break;
229     default:
230       break;
231   }
232   onEdited.notify(Event::PadsEdited);
233 }
234 
polygonsEdited(const PolygonList & list,int index,const std::shared_ptr<const Polygon> & polygon,PolygonList::Event event)235 void Footprint::polygonsEdited(const PolygonList& list, int index,
236                                const std::shared_ptr<const Polygon>& polygon,
237                                PolygonList::Event event) noexcept {
238   Q_UNUSED(list);
239   Q_UNUSED(index);
240   switch (event) {
241     case PolygonList::Event::ElementAdded:
242       if (mRegisteredGraphicsItem) {
243         mRegisteredGraphicsItem->addPolygon(const_cast<Polygon&>(*polygon));
244       }
245       break;
246     case PolygonList::Event::ElementRemoved:
247       if (mRegisteredGraphicsItem) {
248         mRegisteredGraphicsItem->removePolygon(const_cast<Polygon&>(*polygon));
249       }
250       break;
251     default:
252       break;
253   }
254   onEdited.notify(Event::PolygonsEdited);
255 }
256 
circlesEdited(const CircleList & list,int index,const std::shared_ptr<const Circle> & circle,CircleList::Event event)257 void Footprint::circlesEdited(const CircleList& list, int index,
258                               const std::shared_ptr<const Circle>& circle,
259                               CircleList::Event event) noexcept {
260   Q_UNUSED(list);
261   Q_UNUSED(index);
262   switch (event) {
263     case CircleList::Event::ElementAdded:
264       if (mRegisteredGraphicsItem) {
265         mRegisteredGraphicsItem->addCircle(const_cast<Circle&>(*circle));
266       }
267       break;
268     case CircleList::Event::ElementRemoved:
269       if (mRegisteredGraphicsItem) {
270         mRegisteredGraphicsItem->removeCircle(const_cast<Circle&>(*circle));
271       }
272       break;
273     default:
274       break;
275   }
276   onEdited.notify(Event::CirclesEdited);
277 }
278 
strokeTextsEdited(const StrokeTextList & list,int index,const std::shared_ptr<const StrokeText> & text,StrokeTextList::Event event)279 void Footprint::strokeTextsEdited(const StrokeTextList& list, int index,
280                                   const std::shared_ptr<const StrokeText>& text,
281                                   StrokeTextList::Event event) noexcept {
282   Q_UNUSED(list);
283   Q_UNUSED(index);
284   switch (event) {
285     case StrokeTextList::Event::ElementAdded:
286       const_cast<StrokeText&>(*text).setFont(mStrokeFont);
287       if (mRegisteredGraphicsItem) {
288         mRegisteredGraphicsItem->addStrokeText(const_cast<StrokeText&>(*text));
289       }
290       break;
291     case StrokeTextList::Event::ElementRemoved:
292       if (mRegisteredGraphicsItem) {
293         mRegisteredGraphicsItem->removeStrokeText(
294             const_cast<StrokeText&>(*text));
295       }
296       break;
297     default:
298       break;
299   }
300   onEdited.notify(Event::StrokeTextsEdited);
301 }
302 
holesEdited(const HoleList & list,int index,const std::shared_ptr<const Hole> & hole,HoleList::Event event)303 void Footprint::holesEdited(const HoleList& list, int index,
304                             const std::shared_ptr<const Hole>& hole,
305                             HoleList::Event event) noexcept {
306   Q_UNUSED(list);
307   Q_UNUSED(index);
308   switch (event) {
309     case HoleList::Event::ElementAdded:
310       if (mRegisteredGraphicsItem) {
311         mRegisteredGraphicsItem->addHole(const_cast<Hole&>(*hole));
312       }
313       break;
314     case HoleList::Event::ElementRemoved:
315       if (mRegisteredGraphicsItem) {
316         mRegisteredGraphicsItem->removeHole(const_cast<Hole&>(*hole));
317       }
318       break;
319     default:
320       break;
321   }
322   onEdited.notify(Event::HolesEdited);
323 }
324 
325 /*******************************************************************************
326  *  End of File
327  ******************************************************************************/
328 
329 }  // namespace library
330 }  // namespace librepcb
331