1 #include "duplicate_unit.hpp"
2 #include "duplicate_window.hpp"
3 #include "pool/pool.hpp"
4 #include "pool/part.hpp"
5 #include "pool/unit.hpp"
6 #include "pool/symbol.hpp"
7 #include "util/gtk_util.hpp"
8 #include "widgets/location_entry.hpp"
9 #include "util/util.hpp"
10 #include "nlohmann/json.hpp"
11 
12 namespace horizon {
13 
14 class DuplicateSymbolWidget : public Gtk::Box, public Changeable {
15     friend class DuplicateUnitWidget;
16 
17 public:
DuplicateSymbolWidget(Pool & p,const UUID & sym_uuid)18     DuplicateSymbolWidget(Pool &p, const UUID &sym_uuid)
19         : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10), pool(p), sym(*pool.get_symbol(sym_uuid))
20     {
21         auto explain_label = Gtk::manage(new Gtk::Label);
22         explain_label->get_style_context()->add_class("dim-label");
23         explain_label->set_xalign(0);
24         explain_label->set_text("This symbol will be created for the new unit");
25         explain_label->show();
26         explain_label->set_margin_left(20);
27 
28         auto cb = Gtk::manage(new Gtk::CheckButton);
29         auto la = Gtk::manage(new Gtk::Label);
30         la->set_markup("<b>Symbol: " + sym.name + "</b>");
31         cb->add(*la);
32         cb->show_all();
33         cb->set_active(true);
34         cb->signal_toggled().connect([this, cb, explain_label] {
35             if (cb->get_active()) {
36                 explain_label->set_text("This symbol will be created for the new unit");
37             }
38             else {
39                 explain_label->set_text("This symbol won't be created for the new unit");
40             }
41             grid->set_visible(cb->get_active());
42             s_signal_changed.emit();
43         });
44 
45         pack_start(*cb, false, false, 0);
46         pack_start(*explain_label, false, false, 0);
47 
48         grid = Gtk::manage(new Gtk::Grid);
49         grid->set_row_spacing(10);
50         grid->set_column_spacing(10);
51         grid->set_margin_left(20);
52         int top = 0;
53 
54         name_entry = Gtk::manage(new Gtk::Entry);
55         name_entry->set_text(sym.name + " (Copy)");
56         name_entry->set_hexpand(true);
57         grid_attach_label_and_widget(grid, "Name", name_entry, top);
58 
59         location_entry = Gtk::manage(new LocationEntry(pool.get_base_path()));
60         location_entry->set_append_json(true);
61         location_entry->set_rel_filename(
62                 DuplicateUnitWidget::insert_filename(pool.get_rel_filename(ObjectType::SYMBOL, sym.uuid), "-copy"));
63         location_entry->signal_changed().connect([this] { s_signal_changed.emit(); });
64         grid_attach_label_and_widget(grid, "Filename", location_entry, top);
65 
66         grid->show_all();
67 
68 
69         pack_start(*grid, true, true, 0);
70     }
71 
duplicate(const UUID & new_unit_uuid)72     std::string duplicate(const UUID &new_unit_uuid)
73     {
74         if (grid->get_visible()) {
75             Symbol new_sym(sym);
76             new_sym.uuid = UUID::random();
77             new_sym.name = name_entry->get_text();
78             auto new_sym_json = new_sym.serialize();
79             new_sym_json["unit"] = (std::string)new_unit_uuid;
80             auto filename = location_entry->get_filename();
81             ensure_parent_dir(filename);
82             save_json_to_file(filename, new_sym_json);
83             return filename;
84         }
85         else {
86             return "";
87         }
88     }
89 
check_valid()90     bool check_valid()
91     {
92         if (!grid->get_visible())
93             return true;
94 
95         return location_entry->check_ends_json();
96     }
97 
98 private:
99     Pool &pool;
100     const Symbol &sym;
101     Gtk::Entry *name_entry = nullptr;
102     class LocationEntry *location_entry = nullptr;
103     Gtk::Grid *grid = nullptr;
104 };
105 
106 
DuplicateUnitWidget(Pool & p,const UUID & unit_uuid,bool optional)107 DuplicateUnitWidget::DuplicateUnitWidget(Pool &p, const UUID &unit_uuid, bool optional)
108     : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10), pool(p), unit(*pool.get_unit(unit_uuid))
109 {
110     auto la = Gtk::manage(new Gtk::Label);
111     la->set_markup("<b>Unit: " + unit.name + "</b>");
112     la->set_xalign(0);
113     la->show();
114     if (!optional) {
115         pack_start(*la, false, false, 0);
116     }
117     else {
118         auto explain_label = Gtk::manage(new Gtk::Label);
119         explain_label->get_style_context()->add_class("dim-label");
120         explain_label->set_xalign(0);
121         explain_label->set_text("The new entity's gates will reference the new unit");
122         explain_label->show();
123         explain_label->set_margin_left(20);
124 
125         auto cb = Gtk::manage(new Gtk::CheckButton);
126         cb->add(*la);
127         cb->show();
128         cb->set_active(true);
129         cb->signal_toggled().connect([this, cb, explain_label] {
130             grid->set_visible(cb->get_active());
131             if (cb->get_active()) {
132                 explain_label->set_text("The new entity's gates will reference the new unit");
133             }
134             else {
135                 explain_label->set_text(
136                         "The new entity's gates will reference the existing "
137                         "unit");
138             }
139             for (auto ch : get_children()) {
140                 if (auto c = dynamic_cast<DuplicateSymbolWidget *>(ch)) {
141                     c->set_visible(cb->get_active());
142                 }
143             }
144             s_signal_changed.emit();
145         });
146         pack_start(*cb, false, false, 0);
147         pack_start(*explain_label, false, false, 0);
148     }
149 
150     grid = Gtk::manage(new Gtk::Grid);
151     grid->set_row_spacing(10);
152     grid->set_column_spacing(10);
153     if (optional)
154         grid->set_margin_left(20);
155 
156     int top = 0;
157 
158     name_entry = Gtk::manage(new Gtk::Entry);
159     name_entry->set_text(unit.name + " (Copy)");
160     name_entry->set_hexpand(true);
161     grid_attach_label_and_widget(grid, "Name", name_entry, top);
162 
163     location_entry = Gtk::manage(new LocationEntry(pool.get_base_path()));
164     location_entry->set_append_json(true);
165     location_entry->set_rel_filename(insert_filename(pool.get_rel_filename(ObjectType::UNIT, unit.uuid), "-copy"));
166     location_entry->signal_changed().connect([this] { s_signal_changed.emit(); });
167     grid_attach_label_and_widget(grid, "Filename", location_entry, top);
168 
169     grid->show_all();
170     grid->set_margin_bottom(10);
171     pack_start(*grid, false, false, 0);
172 
173     SQLite::Query q(pool.db, "SELECT uuid FROM symbols WHERE unit=?");
174     q.bind(1, unit.uuid);
175     while (q.step()) {
176         auto ws = Gtk::manage(new DuplicateSymbolWidget(pool, UUID(q.get<std::string>(0))));
177         ws->signal_changed().connect([this] { s_signal_changed.emit(); });
178         pack_start(*ws, false, false, 0);
179         ws->show();
180         ws->set_margin_start(10);
181         ws->set_margin_bottom(10);
182     }
183 }
184 
duplicate(std::vector<std::string> * filenames)185 UUID DuplicateUnitWidget::duplicate(std::vector<std::string> *filenames)
186 {
187     if (grid->get_visible()) {
188         Unit new_unit(unit);
189         new_unit.uuid = UUID::random();
190         new_unit.name = name_entry->get_text();
191         const auto filename = location_entry->get_filename();
192         ensure_parent_dir(filename);
193         save_json_to_file(filename, new_unit.serialize());
194         if (filenames)
195             filenames->push_back(location_entry->get_filename());
196 
197         for (auto ch : get_children()) {
198             if (auto c = dynamic_cast<DuplicateSymbolWidget *>(ch)) {
199                 auto symbol_filename = c->duplicate(new_unit.uuid);
200                 if (filenames && symbol_filename.size())
201                     filenames->push_back(symbol_filename);
202             }
203         }
204         return new_unit.uuid;
205     }
206     else {
207         return unit.uuid;
208     }
209 }
210 
get_uuid() const211 UUID DuplicateUnitWidget::get_uuid() const
212 {
213     return unit.uuid;
214 }
215 
insert_filename(const std::string & fn,const std::string & ins)216 std::string DuplicateUnitWidget::insert_filename(const std::string &fn, const std::string &ins)
217 {
218     if (endswith(fn, ".json")) {
219         std::string s(fn);
220         s.resize(s.size() - 5);
221         return s + ins + ".json";
222     }
223     else {
224         return fn;
225     }
226 }
227 
check_valid()228 bool DuplicateUnitWidget::check_valid()
229 {
230     if (!grid->get_visible())
231         return true;
232     bool valid = true;
233     valid = location_entry->check_ends_json() && valid;
234     for (auto ch : get_children()) {
235         if (auto c = dynamic_cast<DuplicateSymbolWidget *>(ch)) {
236             valid = c->check_valid() && valid;
237         }
238     }
239     return valid;
240 }
241 
242 } // namespace horizon
243