1 #include "core_schematic.hpp"
2 #include "core_properties.hpp"
3 #include "pool/part.hpp"
4 #include "util/util.hpp"
5 #include <algorithm>
6 #include "nlohmann/json.hpp"
7 #include <giomm/file.h>
8 #include <glibmm/fileutils.h>
9 #include "pool/ipool.hpp"
10 #include "util/str_util.hpp"
11 #include "util/picture_load.hpp"
12 
13 namespace horizon {
CoreSchematic(const std::string & schematic_filename,const std::string & block_filename,const std::string & pictures_dir,IPool & pool,IPool & pool_caching)14 CoreSchematic::CoreSchematic(const std::string &schematic_filename, const std::string &block_filename,
15                              const std::string &pictures_dir, IPool &pool, IPool &pool_caching)
16     : Core(pool, &pool_caching), block(Block::new_from_file(block_filename, pool_caching)),
17       project_meta_loaded_from_block(block->project_meta.size()),
18       sch(Schematic::new_from_file(schematic_filename, *block, pool_caching)), rules(sch->rules),
19       bom_export_settings(block->bom_export_settings), pdf_export_settings(sch->pdf_export_settings),
20       m_schematic_filename(schematic_filename), m_block_filename(block_filename), m_pictures_dir(pictures_dir)
21 {
22     auto x = std::find_if(sch->sheets.cbegin(), sch->sheets.cend(), [](const auto &a) { return a.second.index == 1; });
23     assert(x != sch->sheets.cend());
24     sheet_uuid = x->first;
25     sch->load_pictures(m_pictures_dir);
26     rebuild();
27 }
28 
get_junction(const UUID & uu)29 Junction *CoreSchematic::get_junction(const UUID &uu)
30 {
31     auto &sheet = sch->sheets.at(sheet_uuid);
32     return &sheet.junctions.at(uu);
33 }
get_schematic_symbol(const UUID & uu)34 SchematicSymbol *CoreSchematic::get_schematic_symbol(const UUID &uu)
35 {
36     auto &sheet = sch->sheets.at(sheet_uuid);
37     return &sheet.symbols.at(uu);
38 }
get_text(const UUID & uu)39 Text *CoreSchematic::get_text(const UUID &uu)
40 {
41     auto &sheet = sch->sheets.at(sheet_uuid);
42     return &sheet.texts.at(uu);
43 }
get_schematic()44 Schematic *CoreSchematic::get_schematic()
45 {
46     return &*sch;
47 }
48 
get_block()49 Block *CoreSchematic::get_block()
50 {
51     return get_schematic()->block;
52 }
53 
get_layer_provider()54 LayerProvider &CoreSchematic::get_layer_provider()
55 {
56     return *get_sheet();
57 }
58 
get_sheet()59 Sheet *CoreSchematic::get_sheet()
60 {
61     return &sch->sheets.at(sheet_uuid);
62 }
63 
get_sheet() const64 const Sheet *CoreSchematic::get_sheet() const
65 {
66     return &sch->sheets.at(sheet_uuid);
67 }
68 
get_line(const UUID & uu)69 Line *CoreSchematic::get_line(const UUID &uu)
70 {
71     auto &sheet = sch->sheets.at(sheet_uuid);
72     return &sheet.lines.at(uu);
73 }
get_arc(const UUID & uu)74 Arc *CoreSchematic::get_arc(const UUID &uu)
75 {
76     auto &sheet = sch->sheets.at(sheet_uuid);
77     return &sheet.arcs.at(uu);
78 }
79 
insert_junction(const UUID & uu)80 Junction *CoreSchematic::insert_junction(const UUID &uu)
81 {
82     auto &sheet = sch->sheets.at(sheet_uuid);
83     auto x = sheet.junctions.emplace(std::make_pair(uu, uu));
84     return &(x.first->second);
85 }
86 
insert_line_net(const UUID & uu)87 LineNet *CoreSchematic::insert_line_net(const UUID &uu)
88 {
89     auto &sheet = sch->sheets.at(sheet_uuid);
90     auto x = sheet.net_lines.emplace(std::make_pair(uu, uu));
91     return &(x.first->second);
92 }
93 
delete_junction(const UUID & uu)94 void CoreSchematic::delete_junction(const UUID &uu)
95 {
96     auto &sheet = sch->sheets.at(sheet_uuid);
97     sheet.junctions.erase(uu);
98 }
delete_line_net(const UUID & uu)99 void CoreSchematic::delete_line_net(const UUID &uu)
100 {
101     auto &sheet = sch->sheets.at(sheet_uuid);
102     sheet.net_lines.erase(uu);
103 }
delete_schematic_symbol(const UUID & uu)104 void CoreSchematic::delete_schematic_symbol(const UUID &uu)
105 {
106     auto &sheet = sch->sheets.at(sheet_uuid);
107     sheet.symbols.erase(uu);
108 }
insert_schematic_symbol(const UUID & uu,const Symbol * sym)109 SchematicSymbol *CoreSchematic::insert_schematic_symbol(const UUID &uu, const Symbol *sym)
110 {
111     auto &sheet = sch->sheets.at(sheet_uuid);
112     auto x = sheet.symbols.emplace(std::make_pair(uu, SchematicSymbol{uu, sym}));
113     return &(x.first->second);
114     return nullptr;
115 }
116 
insert_line(const UUID & uu)117 Line *CoreSchematic::insert_line(const UUID &uu)
118 {
119     auto &sheet = sch->sheets.at(sheet_uuid);
120     auto x = sheet.lines.emplace(std::make_pair(uu, uu));
121     return &(x.first->second);
122 }
delete_line(const UUID & uu)123 void CoreSchematic::delete_line(const UUID &uu)
124 {
125     auto &sheet = sch->sheets.at(sheet_uuid);
126     sheet.lines.erase(uu);
127 }
128 
insert_arc(const UUID & uu)129 Arc *CoreSchematic::insert_arc(const UUID &uu)
130 {
131     auto &sheet = sch->sheets.at(sheet_uuid);
132     auto x = sheet.arcs.emplace(std::make_pair(uu, uu));
133     return &(x.first->second);
134 }
delete_arc(const UUID & uu)135 void CoreSchematic::delete_arc(const UUID &uu)
136 {
137     auto &sheet = sch->sheets.at(sheet_uuid);
138     sheet.arcs.erase(uu);
139 }
140 
get_net_lines()141 std::vector<LineNet *> CoreSchematic::get_net_lines()
142 {
143     auto &sheet = sch->sheets.at(sheet_uuid);
144     std::vector<LineNet *> r;
145     for (auto &it : sheet.net_lines) {
146         r.push_back(&it.second);
147     }
148     return r;
149 }
get_net_labels()150 std::vector<NetLabel *> CoreSchematic::get_net_labels()
151 {
152     auto &sheet = sch->sheets.at(sheet_uuid);
153     std::vector<NetLabel *> r;
154     for (auto &it : sheet.net_labels) {
155         r.push_back(&it.second);
156     }
157     return r;
158 }
159 
get_lines()160 std::vector<Line *> CoreSchematic::get_lines()
161 {
162     auto &sheet = sch->sheets.at(sheet_uuid);
163     std::vector<Line *> r;
164     for (auto &it : sheet.lines) {
165         r.push_back(&it.second);
166     }
167     return r;
168 }
169 
get_arcs()170 std::vector<Arc *> CoreSchematic::get_arcs()
171 {
172     auto &sheet = sch->sheets.at(sheet_uuid);
173     std::vector<Arc *> r;
174     for (auto &it : sheet.arcs) {
175         r.push_back(&it.second);
176     }
177     return r;
178 }
179 
delete_text(const UUID & uu)180 void CoreSchematic::delete_text(const UUID &uu)
181 {
182     auto &sheet = sch->sheets.at(sheet_uuid);
183     sheet.texts.erase(uu);
184 }
insert_text(const UUID & uu)185 Text *CoreSchematic::insert_text(const UUID &uu)
186 {
187     auto &sheet = sch->sheets.at(sheet_uuid);
188     auto x = sheet.texts.emplace(std::make_pair(uu, uu));
189     return &(x.first->second);
190 }
191 
get_picture(const UUID & uu)192 Picture *CoreSchematic::get_picture(const UUID &uu)
193 {
194     auto &sheet = sch->sheets.at(sheet_uuid);
195     return &sheet.pictures.at(uu);
196 }
delete_picture(const UUID & uu)197 void CoreSchematic::delete_picture(const UUID &uu)
198 {
199     auto &sheet = sch->sheets.at(sheet_uuid);
200     sheet.pictures.erase(uu);
201 }
insert_picture(const UUID & uu)202 Picture *CoreSchematic::insert_picture(const UUID &uu)
203 {
204     auto &sheet = sch->sheets.at(sheet_uuid);
205     auto x = sheet.pictures.emplace(std::make_pair(uu, uu));
206     return &(x.first->second);
207 }
208 
has_object_type(ObjectType ty) const209 bool CoreSchematic::has_object_type(ObjectType ty) const
210 {
211     switch (ty) {
212     case ObjectType::JUNCTION:
213     case ObjectType::SCHEMATIC_SYMBOL:
214     case ObjectType::BUS_LABEL:
215     case ObjectType::BUS_RIPPER:
216     case ObjectType::NET_LABEL:
217     case ObjectType::LINE_NET:
218     case ObjectType::POWER_SYMBOL:
219     case ObjectType::TEXT:
220     case ObjectType::LINE:
221     case ObjectType::ARC:
222     case ObjectType::PICTURE:
223         return true;
224         break;
225     default:;
226     }
227 
228     return false;
229 }
230 
get_rules()231 Rules *CoreSchematic::get_rules()
232 {
233     return &rules;
234 }
235 
get_property(ObjectType type,const UUID & uu,ObjectProperty::ID property,PropertyValue & value)236 bool CoreSchematic::get_property(ObjectType type, const UUID &uu, ObjectProperty::ID property, PropertyValue &value)
237 {
238     if (Core::get_property(type, uu, property, value))
239         return true;
240     auto &sheet = sch->sheets.at(sheet_uuid);
241     switch (type) {
242     case ObjectType::NET: {
243         auto net = &block->nets.at(uu);
244         switch (property) {
245         case ObjectProperty::ID::NAME:
246             dynamic_cast<PropertyValueString &>(value).value = net->name;
247             return true;
248 
249         case ObjectProperty::ID::NET_CLASS:
250             dynamic_cast<PropertyValueUUID &>(value).value = net->net_class->uuid;
251             return true;
252 
253         case ObjectProperty::ID::DIFFPAIR: {
254             std::string s;
255             if (net->diffpair) {
256                 s = (net->diffpair_master ? "Master: " : "Slave: ") + net->diffpair->name;
257             }
258             else {
259                 s = "None";
260             }
261             dynamic_cast<PropertyValueString &>(value).value = s;
262             return true;
263         }
264 
265         case ObjectProperty::ID::IS_POWER:
266             dynamic_cast<PropertyValueBool &>(value).value = net->is_power;
267             return true;
268 
269         default:
270             return false;
271         }
272     } break;
273 
274     case ObjectType::NET_LABEL: {
275         auto label = &sheet.net_labels.at(uu);
276         switch (property) {
277         case ObjectProperty::ID::NAME:
278             if (label->junction->net)
279                 dynamic_cast<PropertyValueString &>(value).value = label->junction->net->name;
280             else
281                 dynamic_cast<PropertyValueString &>(value).value = "<no net>";
282             return true;
283 
284         case ObjectProperty::ID::OFFSHEET_REFS:
285             dynamic_cast<PropertyValueBool &>(value).value = label->offsheet_refs;
286             return true;
287 
288         case ObjectProperty::ID::SIZE:
289             dynamic_cast<PropertyValueInt &>(value).value = label->size;
290             return true;
291 
292         default:
293             return false;
294         }
295     } break;
296 
297     case ObjectType::COMPONENT: {
298         auto comp = &block->components.at(uu);
299         switch (property) {
300         case ObjectProperty::ID::REFDES:
301             dynamic_cast<PropertyValueString &>(value).value = comp->refdes;
302             return true;
303 
304         case ObjectProperty::ID::VALUE:
305             if (block->components.at(uu).part)
306                 dynamic_cast<PropertyValueString &>(value).value = comp->part->get_value();
307             else
308                 dynamic_cast<PropertyValueString &>(value).value = comp->value;
309             return true;
310 
311         case ObjectProperty::ID::MPN:
312             if (block->components.at(uu).part)
313                 dynamic_cast<PropertyValueString &>(value).value = comp->part->get_MPN();
314             else
315                 dynamic_cast<PropertyValueString &>(value).value = "<no part>";
316             return true;
317 
318         case ObjectProperty::ID::NOPOPULATE:
319             if (block->components.at(uu).part)
320                 dynamic_cast<PropertyValueBool &>(value).value = comp->nopopulate;
321             else
322                 dynamic_cast<PropertyValueBool &>(value).value = false;
323             return true;
324 
325         default:
326             return false;
327         }
328     } break;
329 
330     case ObjectType::SCHEMATIC_SYMBOL: {
331         auto sym = &sheet.symbols.at(uu);
332         switch (property) {
333         case ObjectProperty::ID::DISPLAY_DIRECTIONS:
334             dynamic_cast<PropertyValueBool &>(value).value = sym->display_directions;
335             return true;
336 
337         case ObjectProperty::ID::DISPLAY_ALL_PADS:
338             dynamic_cast<PropertyValueBool &>(value).value = sym->display_all_pads;
339             return true;
340 
341         case ObjectProperty::ID::PIN_NAME_DISPLAY:
342             dynamic_cast<PropertyValueInt &>(value).value = static_cast<int>(sym->pin_display_mode);
343             return true;
344 
345         case ObjectProperty::ID::EXPAND:
346             dynamic_cast<PropertyValueInt &>(value).value = static_cast<int>(sym->expand);
347             return true;
348 
349         case ObjectProperty::ID::REFDES:
350             dynamic_cast<PropertyValueString &>(value).value = sym->component->refdes + sym->gate->suffix;
351             return true;
352 
353         case ObjectProperty::ID::VALUE:
354             dynamic_cast<PropertyValueString &>(value).value = sym->custom_value;
355             return true;
356 
357         default:
358             return false;
359         }
360     } break;
361 
362     default:
363         return false;
364     }
365 }
366 
set_property(ObjectType type,const UUID & uu,ObjectProperty::ID property,const PropertyValue & value)367 bool CoreSchematic::set_property(ObjectType type, const UUID &uu, ObjectProperty::ID property,
368                                  const PropertyValue &value)
369 {
370     if (Core::set_property(type, uu, property, value))
371         return true;
372     auto &sheet = sch->sheets.at(sheet_uuid);
373     switch (type) {
374     case ObjectType::COMPONENT: {
375         auto comp = &block->components.at(uu);
376         switch (property) {
377         case ObjectProperty::ID::REFDES:
378             comp->refdes = dynamic_cast<const PropertyValueString &>(value).value;
379             break;
380 
381         case ObjectProperty::ID::VALUE:
382             if (comp->part)
383                 return false;
384             comp->value = dynamic_cast<const PropertyValueString &>(value).value;
385             break;
386 
387         case ObjectProperty::ID::NOPOPULATE:
388             comp->nopopulate = dynamic_cast<const PropertyValueBool &>(value).value;
389             break;
390 
391         default:
392             return false;
393         }
394     } break;
395 
396     case ObjectType::NET: {
397         auto net = &block->nets.at(uu);
398         switch (property) {
399         case ObjectProperty::ID::NAME:
400             net->name = dynamic_cast<const PropertyValueString &>(value).value;
401             break;
402 
403         case ObjectProperty::ID::NET_CLASS: {
404             net->net_class = &block->net_classes.at(dynamic_cast<const PropertyValueUUID &>(value).value);
405         } break;
406 
407         case ObjectProperty::ID::IS_POWER:
408             if (block->nets.at(uu).is_power_forced)
409                 return false;
410             block->nets.at(uu).is_power = dynamic_cast<const PropertyValueBool &>(value).value;
411             break;
412 
413         default:
414             return false;
415         }
416     } break;
417 
418     case ObjectType::SCHEMATIC_SYMBOL: {
419         auto sym = &sheet.symbols.at(uu);
420         switch (property) {
421         case ObjectProperty::ID::DISPLAY_DIRECTIONS:
422             sym->display_directions = dynamic_cast<const PropertyValueBool &>(value).value;
423             break;
424 
425         case ObjectProperty::ID::DISPLAY_ALL_PADS:
426             sym->display_all_pads = dynamic_cast<const PropertyValueBool &>(value).value;
427             break;
428 
429         case ObjectProperty::ID::PIN_NAME_DISPLAY:
430             sym->pin_display_mode =
431                     static_cast<SchematicSymbol::PinDisplayMode>(dynamic_cast<const PropertyValueInt &>(value).value);
432             break;
433 
434         case ObjectProperty::ID::EXPAND:
435             sym->expand = dynamic_cast<const PropertyValueInt &>(value).value;
436             sym->apply_expand();
437             break;
438 
439         case ObjectProperty::ID::VALUE:
440             sym->custom_value = dynamic_cast<const PropertyValueString &>(value).value;
441             trim(sym->custom_value);
442             break;
443 
444         default:
445             return false;
446         }
447     } break;
448 
449     case ObjectType::NET_LABEL: {
450         auto label = &sheet.net_labels.at(uu);
451         switch (property) {
452         case ObjectProperty::ID::OFFSHEET_REFS:
453             label->offsheet_refs = dynamic_cast<const PropertyValueBool &>(value).value;
454             break;
455 
456         case ObjectProperty::ID::SIZE:
457             label->size = dynamic_cast<const PropertyValueInt &>(value).value;
458             break;
459 
460         default:
461             return false;
462         }
463     } break;
464 
465     default:
466         return false;
467     }
468     if (!property_transaction) {
469         rebuild(false);
470         set_needs_save(true);
471     }
472     return true;
473 }
474 
get_property_meta(ObjectType type,const UUID & uu,ObjectProperty::ID property,PropertyMeta & meta)475 bool CoreSchematic::get_property_meta(ObjectType type, const UUID &uu, ObjectProperty::ID property, PropertyMeta &meta)
476 {
477     if (Core::get_property_meta(type, uu, property, meta))
478         return true;
479     auto &sheet = sch->sheets.at(sheet_uuid);
480     switch (type) {
481     case ObjectType::NET:
482         switch (property) {
483         case ObjectProperty::ID::IS_POWER:
484             meta.is_settable = !block->nets.at(uu).is_power_forced;
485             return true;
486 
487         case ObjectProperty::ID::NET_CLASS: {
488             PropertyMetaNetClasses &m = dynamic_cast<PropertyMetaNetClasses &>(meta);
489             m.net_classes.clear();
490             for (const auto &it : block->net_classes) {
491                 m.net_classes.emplace(it.first, it.second.name);
492             }
493             return true;
494         }
495 
496         default:
497             return false;
498         }
499         break;
500 
501     case ObjectType::COMPONENT:
502         switch (property) {
503         case ObjectProperty::ID::VALUE:
504             meta.is_settable = block->components.at(uu).part == nullptr;
505             return true;
506 
507         default:
508             return false;
509         }
510         break;
511 
512     case ObjectType::SCHEMATIC_SYMBOL:
513         switch (property) {
514         case ObjectProperty::ID::EXPAND:
515             meta.is_settable = sheet.symbols.at(uu).pool_symbol->can_expand;
516             return true;
517 
518         default:
519             return false;
520         }
521         break;
522 
523     case ObjectType::TEXT:
524         switch (property) {
525         case ObjectProperty::ID::ALLOW_UPSIDE_DOWN:
526             meta.is_visible = false;
527             return true;
528         default:
529             return false;
530         }
531         break;
532 
533     default:
534         return false;
535     }
536     return false;
537 }
538 
get_display_name(ObjectType type,const UUID & uu)539 std::string CoreSchematic::get_display_name(ObjectType type, const UUID &uu)
540 {
541     return get_display_name(type, uu, sheet_uuid);
542 }
543 
get_display_name(ObjectType type,const UUID & uu,const UUID & sh)544 std::string CoreSchematic::get_display_name(ObjectType type, const UUID &uu, const UUID &sh)
545 {
546     auto &sheet = sch->sheets.at(sh);
547     switch (type) {
548     case ObjectType::NET:
549         return block->nets.at(uu).name;
550 
551     case ObjectType::LINE_NET: {
552         const auto &li = sheet.net_lines.at(uu);
553         return li.net ? li.net->name : "";
554     }
555 
556     case ObjectType::JUNCTION: {
557         const auto &ju = sheet.junctions.at(uu);
558         return ju.net ? ju.net->name : "";
559     }
560 
561     case ObjectType::NET_LABEL: {
562         const auto &la = sheet.net_labels.at(uu);
563         return la.junction->net ? la.junction->net->name : "";
564     }
565 
566     case ObjectType::SCHEMATIC_SYMBOL:
567         return sheet.symbols.at(uu).component->refdes + sheet.symbols.at(uu).gate->suffix;
568 
569     case ObjectType::COMPONENT:
570         return block->components.at(uu).refdes;
571 
572     case ObjectType::POWER_SYMBOL:
573         return sheet.power_symbols.at(uu).net->name;
574 
575     case ObjectType::BUS_RIPPER:
576         return sheet.bus_rippers.at(uu).bus_member->net->name;
577 
578     case ObjectType::TEXT:
579         return sheet.texts.at(uu).text;
580 
581     default:
582         return Core::get_display_name(type, uu);
583     }
584 }
585 
add_sheet()586 void CoreSchematic::add_sheet()
587 {
588     auto uu = UUID::random();
589     auto sheet_max = std::max_element(sch->sheets.begin(), sch->sheets.end(),
590                                       [](const auto &p1, const auto &p2) { return p1.second.index < p2.second.index; });
591     auto *sheet = &sch->sheets.emplace(uu, uu).first->second;
592     sheet->index = sheet_max->second.index + 1;
593     sheet->name = "sheet " + std::to_string(sheet->index);
594     sheet->pool_frame = sch->sheets.at(sheet_uuid).pool_frame;
595     rebuild();
596 }
597 
delete_sheet(const UUID & uu)598 void CoreSchematic::delete_sheet(const UUID &uu)
599 {
600     if (sch->sheets.size() <= 1)
601         return;
602     if (sch->sheets.at(uu).symbols.size() > 0) // only delete empty sheets
603         return;
604     auto deleted_index = sch->sheets.at(uu).index;
605     sch->sheets.erase(uu);
606     for (auto &it : sch->sheets) {
607         if (it.second.index > deleted_index) {
608             it.second.index--;
609         }
610     }
611     if (sheet_uuid == uu) { // deleted current sheet
612         auto x = std::find_if(sch->sheets.begin(), sch->sheets.end(), [](auto e) { return e.second.index == 1; });
613         sheet_uuid = x->first;
614     }
615     rebuild();
616 }
617 
set_sheet(const UUID & uu)618 void CoreSchematic::set_sheet(const UUID &uu)
619 {
620     if (tool_is_active())
621         return;
622     if (sch->sheets.count(uu) == 0)
623         return;
624     sheet_uuid = uu;
625 }
626 
rebuild(bool from_undo)627 void CoreSchematic::rebuild(bool from_undo)
628 {
629     clock_t begin = clock();
630     sch->expand();
631     Core::rebuild(from_undo);
632     clock_t end = clock();
633     double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
634     std::cout << "rebuild took " << elapsed_secs << std::endl;
635 }
636 
get_canvas_data()637 const Sheet &CoreSchematic::get_canvas_data()
638 {
639     return sch->sheets.at(sheet_uuid);
640 }
641 
history_push()642 void CoreSchematic::history_push()
643 {
644     history.push_back(std::make_unique<CoreSchematic::HistoryItem>(*block, *sch));
645     auto x = dynamic_cast<CoreSchematic::HistoryItem *>(history.back().get());
646     x->sch.block = &x->block;
647     x->sch.update_refs();
648 }
649 
history_load(unsigned int i)650 void CoreSchematic::history_load(unsigned int i)
651 {
652     const auto &x = dynamic_cast<CoreSchematic::HistoryItem &>(*history.at(history_current));
653     sch.emplace(x.sch);
654     block.emplace(x.block);
655     sch->block = &*block;
656     sch->update_refs();
657     s_signal_rebuilt.emit();
658 }
659 
reload_pool()660 void CoreSchematic::reload_pool()
661 {
662     PictureKeeper keeper;
663     for (const auto &[uu_sheet, sheet] : sch->sheets) {
664         keeper.save(sheet.pictures);
665     }
666     const auto sch_j = sch->serialize();
667     const auto block_j = block->serialize();
668     m_pool.clear();
669     m_pool_caching.clear();
670     block.emplace(block->uuid, block_j, m_pool_caching);
671     sch.emplace(sch->uuid, sch_j, *block, m_pool_caching);
672     for (auto &[uu_sheet, sheet] : sch->sheets) {
673         keeper.restore(sheet.pictures);
674     }
675     bom_export_settings.update_refs(m_pool_caching);
676     history_clear();
677     rebuild();
678 }
679 
get_bbox()680 std::pair<Coordi, Coordi> CoreSchematic::get_bbox()
681 {
682     return get_sheet()->frame.get_bbox();
683 }
684 
get_filename() const685 const std::string &CoreSchematic::get_filename() const
686 {
687     return m_schematic_filename;
688 }
689 
save(const std::string & suffix)690 void CoreSchematic::save(const std::string &suffix)
691 {
692     sch->rules = rules;
693     block->bom_export_settings = bom_export_settings;
694     sch->pdf_export_settings = pdf_export_settings;
695     save_json_to_file(m_schematic_filename + suffix, sch->serialize());
696     save_json_to_file(m_block_filename + suffix, block->serialize());
697     sch->save_pictures(m_pictures_dir);
698 }
699 
700 
delete_autosave()701 void CoreSchematic::delete_autosave()
702 {
703     if (Glib::file_test(m_schematic_filename + autosave_suffix, Glib::FILE_TEST_IS_REGULAR))
704         Gio::File::create_for_path(m_schematic_filename + autosave_suffix)->remove();
705     if (Glib::file_test(m_block_filename + autosave_suffix, Glib::FILE_TEST_IS_REGULAR))
706         Gio::File::create_for_path(m_block_filename + autosave_suffix)->remove();
707 }
708 
709 } // namespace horizon
710