/[svn]/gigedit/trunk/src/gigedit/MacroEditor.cpp
ViewVC logotype

Contents of /gigedit/trunk/src/gigedit/MacroEditor.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3154 - (show annotations) (download)
Sat May 6 13:46:14 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 11169 byte(s)
* WIP Macro Editor: Implemented deleting of rows.
* WIP Macro Editor: Implemented changing values 
  of rows.
* WIP Macro Editor: show type column in gray color.
* Bumped version (1.0.0.svn36).

1 /*
2 Copyright (c) MMXVII Christian Schoenebeck
3
4 This file is part of "gigedit" and released under the terms of the
5 GNU General Public License version 2.
6 */
7
8 #include "MacroEditor.h"
9 #include "global.h"
10 #include <assert.h>
11
12 MacroEditor::MacroEditor() :
13 m_macroOriginal(NULL),
14 m_statusLabel("", Gtk::ALIGN_START),
15 m_deleteButton(_("Delete")),
16 m_inverseDeleteButton(_("Inverse Delete")),
17 m_applyButton(_("_Apply"), true),
18 m_cancelButton(_("_Cancel"), true)
19 {
20 add(m_vbox);
21
22 set_default_size(800, 600);
23
24 // create Macro treeview (including its data model)
25 m_treeStoreMacro = MacroTreeStore::create(m_treeModelMacro);
26 m_treeViewMacro.set_model(m_treeStoreMacro);
27 m_treeViewMacro.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
28 //m_treeViewMacro.set_tooltip_text(_(""));
29 m_treeViewMacro.append_column(_("Key"), m_treeModelMacro.m_col_name);
30 m_treeViewMacro.append_column(_("Type"), m_treeModelMacro.m_col_type);
31 m_treeViewMacro.append_column_editable(_("Value"), m_treeModelMacro.m_col_value);
32 {
33 Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(1);
34 Gtk::CellRendererText* cellrenderer =
35 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
36 cellrenderer->property_foreground().set_value("#bababa");
37 }
38 /*{
39 Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(0);
40 Gtk::CellRendererText* cellrenderer =
41 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
42 column->add_attribute(
43 cellrenderer->property_foreground(), m_SamplesModel.m_color
44 );
45 }*/
46 /*{
47 Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(1);
48 Gtk::CellRendererText* cellrenderer =
49 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
50 column->add_attribute(
51 cellrenderer->property_foreground(), m_SamplesModel.m_color
52 );
53 }*/
54 m_treeViewMacro.set_headers_visible(true);
55 m_treeViewMacro.get_selection()->signal_changed().connect(
56 sigc::mem_fun(*this, &MacroEditor::onTreeViewSelectionChanged)
57 );
58 m_treeViewMacro.signal_key_release_event().connect_notify(
59 sigc::mem_fun(*this, &MacroEditor::onMacroTreeViewKeyRelease)
60 );
61 m_treeStoreMacro->signal_row_changed().connect(
62 sigc::mem_fun(*this, &MacroEditor::onMacroTreeViewRowValueChanged)
63 );
64 m_ignoreTreeViewValueChange = false;
65
66 m_scrolledWindow.add(m_treeViewMacro);
67 m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
68 m_vbox.pack_start(m_scrolledWindow);
69
70 m_buttonBoxL.set_layout(Gtk::BUTTONBOX_START);
71 m_buttonBoxL.pack_start(m_deleteButton);
72 m_buttonBoxL.pack_start(m_inverseDeleteButton);
73 m_deleteButton.set_sensitive(false);
74 m_inverseDeleteButton.set_sensitive(false);
75
76 m_buttonBox.set_layout(Gtk::BUTTONBOX_END);
77 m_buttonBox.pack_start(m_applyButton);
78 m_buttonBox.pack_start(m_cancelButton);
79 m_applyButton.set_can_default();
80 m_applyButton.set_sensitive(false);
81 m_applyButton.grab_focus();
82
83 #if GTKMM_MAJOR_VERSION >= 3
84 m_statusLabel.set_margin_left(6);
85 m_statusLabel.set_margin_right(6);
86 #else
87 m_statusHBox.set_spacing(6);
88 #endif
89
90 m_statusHBox.pack_start(m_statusLabel);
91 m_statusHBox.show_all_children();
92
93 m_footerHBox.pack_start(m_buttonBoxL, Gtk::PACK_SHRINK);
94 m_footerHBox.pack_start(m_statusHBox);
95 m_footerHBox.pack_start(m_buttonBox, Gtk::PACK_SHRINK);
96
97 m_vbox.pack_start(m_footerHBox, Gtk::PACK_SHRINK);
98
99 m_applyButton.signal_clicked().connect(
100 sigc::mem_fun(*this, &MacroEditor::onButtonApply)
101 );
102
103 m_cancelButton.signal_clicked().connect(
104 sigc::mem_fun(*this, &MacroEditor::onButtonCancel)
105 );
106
107 m_deleteButton.signal_clicked().connect(
108 sigc::mem_fun(*this, &MacroEditor::deleteSelectedRows)
109 );
110
111 m_inverseDeleteButton.signal_clicked().connect(
112 sigc::mem_fun(*this, &MacroEditor::inverseDeleteSelectedRows)
113 );
114
115 signal_hide().connect(
116 sigc::mem_fun(*this, &MacroEditor::onWindowHide)
117 );
118
119 signal_delete_event().connect(
120 sigc::mem_fun(*this, &MacroEditor::onWindowDelete)
121 );
122
123 show_all_children();
124 updateStatus();
125 }
126
127 MacroEditor::~MacroEditor() {
128 printf("MacroEditor destruct\n");
129 }
130
131 void MacroEditor::setMacro(Serialization::Archive* macro) {
132 m_macroOriginal = macro;
133 if (!macro) {
134 set_title(_("No Macro"));
135 return;
136 }
137
138 //set_title(std::string(_("Macro Editor:")) + " \"" + macro->name() + "\"");
139 set_title(std::string(_("Macro Editor:")));
140
141 // copy for non-destructive editing
142 m_macro = *macro;
143
144 reloadTreeView();
145 }
146
147 void MacroEditor::buildTreeView(const Gtk::TreeModel::Row& parentRow, const Serialization::Object& parentObject) {
148 for (int iMember = 0; iMember < parentObject.members().size(); ++iMember) {
149 const Serialization::Member& member = parentObject.members()[iMember];
150 const Serialization::Object& object = m_macro.objectByUID(member.uid());
151 Gtk::TreeModel::iterator iterRow = m_treeStoreMacro->append(parentRow.children());
152 Gtk::TreeModel::Row row = *iterRow;
153 row[m_treeModelMacro.m_col_name] = gig_to_utf8(member.name());
154 row[m_treeModelMacro.m_col_type] = gig_to_utf8(member.type().asLongDescr());
155 row[m_treeModelMacro.m_col_uid] = object.uid();
156 if (object.type().isClass()) {
157 row[m_treeModelMacro.m_col_value] = "(class)";
158 buildTreeView(row, object);
159 } else {
160 row[m_treeModelMacro.m_col_value] = m_macro.valueAsString(object);
161 }
162 }
163 }
164
165 void MacroEditor::reloadTreeView() {
166 m_ignoreTreeViewValueChange = true;
167
168 m_treeStoreMacro->clear();
169
170 const Serialization::Object& rootObject = m_macro.rootObject();
171
172 Gtk::TreeModel::iterator iterRoot = m_treeStoreMacro->append();
173 Gtk::TreeModel::Row rowRoot = *iterRoot;
174 rowRoot[m_treeModelMacro.m_col_name] = "(Root)";
175 rowRoot[m_treeModelMacro.m_col_type] = gig_to_utf8(rootObject.type().asLongDescr());
176 rowRoot[m_treeModelMacro.m_col_value] = "";
177 rowRoot[m_treeModelMacro.m_col_uid] = rootObject.uid();
178
179 buildTreeView(rowRoot, rootObject);
180
181 m_treeViewMacro.expand_all();
182
183 updateStatus();
184
185 m_ignoreTreeViewValueChange = false;
186 }
187
188 void MacroEditor::onTreeViewSelectionChanged() {
189 std::vector<Gtk::TreeModel::Path> v = m_treeViewMacro.get_selection()->get_selected_rows();
190 const bool bValidSelection = !v.empty();
191 m_deleteButton.set_sensitive(bValidSelection);
192 m_inverseDeleteButton.set_sensitive(bValidSelection);
193 }
194
195 void MacroEditor::onMacroTreeViewKeyRelease(GdkEventKey* key) {
196 if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete)
197 deleteSelectedRows();
198 }
199
200 void MacroEditor::onMacroTreeViewRowValueChanged(const Gtk::TreeModel::Path& path,
201 const Gtk::TreeModel::iterator& iter)
202 {
203 if (m_ignoreTreeViewValueChange) return;
204 if (!iter) return;
205 Gtk::TreeModel::Row row = *iter;
206 Glib::ustring value = row[m_treeModelMacro.m_col_value];
207 Serialization::UID uid = row[m_treeModelMacro.m_col_uid];
208 Serialization::String gigvalue(gig_from_utf8(value));
209 Serialization::Object& object = m_macro.objectByUID(uid);
210 std::string errorText;
211 try {
212 m_macro.setAutoValue(object, gigvalue);
213 } catch (Serialization::Exception e) {
214 errorText = e.Message;
215 } catch (...) {
216 errorText = _("Unknown exception during object value change");
217 }
218 if (!errorText.empty()) {
219 Glib::ustring txt = _("Couldn't change value:\n") + errorText;
220 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
221 msg.run();
222 }
223 }
224
225 void MacroEditor::deleteSelectedRows() {
226 Glib::RefPtr<Gtk::TreeSelection> sel = m_treeViewMacro.get_selection();
227 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
228 for (int r = rows.size() - 1; r >= 0; --r) {
229 Gtk::TreeModel::iterator it = m_treeStoreMacro->get_iter(rows[r]);
230 if (!it) continue;
231 Gtk::TreeModel::Row row = *it;
232 Serialization::UID uid = row[m_treeModelMacro.m_col_uid];
233 if (uid == m_macro.rootObject().uid()) continue; // prohibit deleting root object
234 Gtk::TreeModel::iterator itParent = row.parent();
235 if (!itParent) continue;
236 Gtk::TreeModel::Row rowParent = *itParent;
237 Serialization::UID uidParent = rowParent[m_treeModelMacro.m_col_uid];
238 //Serialization::Object& object = m_macro.objectByUID(uid);
239 Serialization::Object& parentObject = m_macro.objectByUID(uidParent);
240 const Serialization::Member& member = parentObject.memberByUID(uid);
241 m_macro.removeMember(parentObject, member);
242 //m_macro.remove(object);
243 }
244 reloadTreeView();
245 }
246
247 void MacroEditor::inverseDeleteSelectedRows() {
248 }
249
250 void MacroEditor::updateStatus() {
251 m_applyButton.set_sensitive(isModified());
252 updateStatusBar();
253 }
254
255 void MacroEditor::updateStatusBar() {
256 // update status text
257 std::string txt;
258 m_statusLabel.set_markup(txt);
259 }
260
261 bool MacroEditor::onWindowDelete(GdkEventAny* e) {
262 //printf("onWindowDelete\n");
263
264 if (!isModified()) return false; // propagate event further (which will close this window)
265
266 //gchar* msg = g_strdup_printf(_("Apply changes to macro \"%s\" before closing?"),
267 // m_macroOriginal->Name.c_str());
268 gchar* msg = g_strdup_printf(_("Apply changes to macro before closing?"));
269 Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
270 g_free(msg);
271 dialog.set_secondary_text(_("If you close without applying, your changes will be lost."));
272 dialog.add_button(_("Close _Without Applying"), Gtk::RESPONSE_NO);
273 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
274 dialog.add_button(_("_Apply"), Gtk::RESPONSE_YES);
275 dialog.set_default_response(Gtk::RESPONSE_YES);
276 int response = dialog.run();
277 dialog.hide();
278
279 // user decided to close macro editor without saving
280 if (response == Gtk::RESPONSE_NO)
281 return false; // propagate event further (which will close this window)
282
283 // user cancelled dialog, thus don't close macro editor
284 if (response == Gtk::RESPONSE_CANCEL) {
285 show();
286 return true; // drop event (prevents closing this window)
287 }
288
289 // user wants to apply the changes, afterwards close window
290 if (response == Gtk::RESPONSE_YES) {
291 onButtonApply();
292 return false; // propagate event further (which will close this window)
293 }
294
295 // should never ever make it to this point actually
296 return false;
297 }
298
299 bool MacroEditor::isModified() const {
300 return m_macro.isModified();
301 }
302
303 void MacroEditor::onButtonCancel() {
304 bool dropEvent = onWindowDelete(NULL);
305 if (dropEvent) return;
306 hide();
307 }
308
309 void MacroEditor::onButtonApply() {
310 //m_macro.encode();
311 *m_macroOriginal = m_macro;
312 }
313
314 void MacroEditor::onWindowHide() {
315 delete this; // this is the end, my friend
316 }

  ViewVC Help
Powered by ViewVC