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