/[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 3456 - (show annotations) (download)
Sun Jan 27 10:07:56 2019 UTC (5 years, 2 months ago) by persson
File size: 22741 byte(s)
* Fixed some compiler warnings

1 /*
2 Copyright (c) MMXVII - MMXIX 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(Glib::ustring(_("Delete")) + " " + UNICODE_PRIMARY_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
16 m_inverseDeleteButton(Glib::ustring(_("Inverse Delete")) + " " + UNICODE_ALT_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
17 m_applyButton(_("_Apply"), true),
18 m_cancelButton(_("_Cancel"), true),
19 m_altKeyDown(false),
20 m_primaryKeyDown(false)
21 {
22 add(m_vbox);
23
24 if (!Settings::singleton()->autoRestoreWindowDimension) {
25 set_default_size(800, 600);
26 set_position(Gtk::WIN_POS_MOUSE);
27 }
28
29 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 12)
30 m_labelIntro.set_margin_start(10);
31 m_labelIntro.set_margin_end(10);
32 #else
33 m_labelIntro.set_padding(10, 10);
34 #endif
35 #if GTKMM_MAJOR_VERSION >= 3
36 m_labelIntro.set_line_wrap();
37 #endif
38 m_labelIntro.set_text(
39 _("A macro is a list of parameters and corresponding values which "
40 "should be applied to the instrument editor when the macro is "
41 "triggered by the user. Only the parameters listed here will be "
42 "applied to the instrument editor when this macro is triggered, all "
43 "other ones remain untouched. So simply delete parameters here which "
44 "you don't want to be modified by this macro. Double click on a "
45 "value to change it.")
46 );
47 m_vbox.pack_start(m_labelIntro, Gtk::PACK_SHRINK);
48
49 // create Macro treeview (including its data model)
50 m_treeStoreMacro = MacroTreeStore::create(m_treeModelMacro);
51 m_treeViewMacro.set_model(m_treeStoreMacro);
52 m_treeViewMacro.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
53 //m_treeViewMacro.set_tooltip_text(_(""));
54 m_treeViewMacro.append_column(_("Key"), m_treeModelMacro.m_col_name);
55 m_treeViewMacro.append_column(_("Type"), m_treeModelMacro.m_col_type);
56 //m_treeViewMacro.append_column_editable(_("Value"), m_treeModelMacro.m_col_value);
57 //m_treeViewMacro.append_column(_("Value"), m_valueCellRenderer);
58 Gtk::TreeViewColumn* valueColumn = new Gtk::TreeViewColumn(_("Value"));
59 valueColumn->pack_start(m_valueCellRenderer);
60 m_treeViewMacro.append_column(*valueColumn);
61 // m_valueCellRenderer.property_model() = m_comboBoxModel;
62 // m_valueCellRenderer.property_text_column() = 0;
63 //m_valueCellRenderer.property_editable() = true;
64 {
65 Gtk::TreeView::Column* column = valueColumn;// m_treeViewMacro.get_column(2);
66 //column->set_renderer(m_valueCellRenderer, m_treeModelMacro.m_col_value);
67 column->add_attribute(m_valueCellRenderer.property_text(),
68 m_treeModelMacro.m_col_value);
69 column->add_attribute(m_valueCellRenderer.property_has_entry(),
70 m_treeModelMacro.m_col_allowTextEntry);
71 column->add_attribute(m_valueCellRenderer.property_editable(),
72 m_treeModelMacro.m_col_editable);
73 column->add_attribute(m_valueCellRenderer.property_model(),
74 m_treeModelMacro.m_col_options);
75 }
76 m_valueCellRenderer.property_text_column() = 0;
77 m_valueCellRenderer.signal_edited().connect(
78 sigc::mem_fun(*this, &MacroEditor::onValueCellEdited)
79 );
80
81 {
82 Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(1);
83 Gtk::CellRendererText* cellrenderer =
84 dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
85 cellrenderer->property_foreground().set_value("#bababa");
86 }
87 m_treeViewMacro.set_headers_visible(true);
88 m_treeViewMacro.get_selection()->signal_changed().connect(
89 sigc::mem_fun(*this, &MacroEditor::onTreeViewSelectionChanged)
90 );
91 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
92 m_treeViewMacro.signal_key_release_event().connect(
93 #else
94 m_treeViewMacro.signal_key_release_event().connect_notify(
95 #endif
96 sigc::mem_fun(*this, &MacroEditor::onMacroTreeViewKeyRelease)
97 );
98 m_treeStoreMacro->signal_row_changed().connect(
99 sigc::mem_fun(*this, &MacroEditor::onMacroTreeViewRowValueChanged)
100 );
101 m_ignoreTreeViewValueChange = false;
102
103 m_scrolledWindow.add(m_treeViewMacro);
104 m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
105 m_vbox.pack_start(m_scrolledWindow);
106
107 m_buttonBoxL.set_layout(Gtk::BUTTONBOX_START);
108 m_buttonBoxL.pack_start(m_deleteButton);
109 m_buttonBoxL.pack_start(m_inverseDeleteButton);
110 m_deleteButton.set_sensitive(false);
111 m_inverseDeleteButton.set_sensitive(false);
112
113 m_buttonBox.set_layout(Gtk::BUTTONBOX_END);
114 m_buttonBox.pack_start(m_applyButton);
115 m_buttonBox.pack_start(m_cancelButton);
116 m_applyButton.set_can_default();
117 m_applyButton.set_sensitive(false);
118 m_applyButton.grab_focus();
119
120 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 12)
121 m_labelIntro.set_margin_start(6);
122 m_labelIntro.set_margin_end(6);
123 #elif GTKMM_MAJOR_VERSION >= 3
124 m_statusLabel.set_margin_left(6);
125 m_statusLabel.set_margin_right(6);
126 #else
127 m_statusHBox.set_spacing(6);
128 #endif
129
130 m_statusHBox.pack_start(m_statusLabel);
131 #if HAS_GTKMM_SHOW_ALL_CHILDREN
132 m_statusHBox.show_all_children();
133 #endif
134
135 m_footerHBox.pack_start(m_buttonBoxL, Gtk::PACK_SHRINK);
136 m_footerHBox.pack_start(m_statusHBox);
137 m_footerHBox.pack_start(m_buttonBox, Gtk::PACK_SHRINK);
138
139 m_vbox.pack_start(m_footerHBox, Gtk::PACK_SHRINK);
140
141 m_applyButton.signal_clicked().connect(
142 sigc::mem_fun(*this, &MacroEditor::onButtonApply)
143 );
144
145 m_cancelButton.signal_clicked().connect(
146 sigc::mem_fun(*this, &MacroEditor::onButtonCancel)
147 );
148
149 m_deleteButton.signal_clicked().connect(
150 sigc::mem_fun(*this, &MacroEditor::deleteSelectedRows)
151 );
152
153 m_inverseDeleteButton.signal_clicked().connect(
154 sigc::mem_fun(*this, &MacroEditor::inverseDeleteSelectedRows)
155 );
156
157 signal_hide().connect(
158 sigc::mem_fun(*this, &MacroEditor::onWindowHide)
159 );
160
161 signal_delete_event().connect(
162 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
163 sigc::mem_fun(*this, &MacroEditor::onWindowDelete)
164 #else
165 sigc::mem_fun(*this, &MacroEditor::onWindowDeleteP)
166 #endif
167 );
168
169 signal_key_press_event().connect(
170 sigc::mem_fun(*this, &MacroEditor::onKeyPressed)
171 );
172 signal_key_release_event().connect(
173 sigc::mem_fun(*this, &MacroEditor::onKeyReleased)
174 );
175
176 m_deleteButton.set_tooltip_text(_("Delete the selected parameters from this macro."));
177 m_inverseDeleteButton.set_tooltip_text(_("Delete all parameters from this macro except the selected ones."));
178
179 #if HAS_GTKMM_SHOW_ALL_CHILDREN
180 show_all_children();
181 #endif
182 updateStatus();
183 }
184
185 MacroEditor::~MacroEditor() {
186 printf("MacroEditor destruct\n");
187 }
188
189 void MacroEditor::setMacro(Serialization::Archive* macro, bool isClipboard) {
190 m_macroOriginal = macro;
191 if (!macro) {
192 set_title(_("No Macro"));
193 return;
194 }
195
196 if (isClipboard)
197 set_title(std::string(_("Macro Editor:")) + " " + _("Clipboard Content"));
198 else {
199 if (macro->name().empty())
200 set_title(std::string(_("Macro Editor:")) + " " + _("Unnamed Macro"));
201 else
202 set_title(std::string(_("Macro Editor:")) + " \"" + macro->name() + "\"");
203 }
204
205 // copy for non-destructive editing
206 m_macro = *macro;
207
208 reloadTreeView();
209 }
210
211 sigc::signal<void>& MacroEditor::signal_changes_applied() {
212 return m_changes_applied;
213 }
214
215 Glib::RefPtr<Gtk::ListStore> MacroEditor::createComboOptions(const char** options) {
216 Glib::RefPtr<Gtk::ListStore> refOptions = Gtk::ListStore::create(m_comboOptionsModel);
217 for (size_t i = 0; options[i]; ++i)
218 (*refOptions->append())[m_comboOptionsModel.m_col_choice] = options[i];
219 return refOptions;
220 }
221
222 inline static Serialization::String _boolToStr(bool b) {
223 // 'NO' intentional all uper case in contrast to 'Yes', simply because I
224 // find them easier distinguishable that way on quick readings
225 return b ? "Yes" : "NO";
226 }
227
228 static const char* _boolOptions[] = { "Yes", "NO", NULL };
229
230 void MacroEditor::buildTreeView(const Gtk::TreeModel::Row& parentRow, const Serialization::Object& parentObject) {
231 for (int iMember = 0; iMember < parentObject.members().size(); ++iMember) {
232 const Serialization::Member& member = parentObject.members()[iMember];
233 const Serialization::Object& object = m_macro.objectByUID(member.uid());
234
235 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
236 //HACK: on GTKMM 3.9x append() below requires TreeNodeChildren, parentRow.children() returns TreeNodeConstChildren though, probably going to be fixed before final GTKMM4 release though.
237 const Gtk::TreeNodeConstChildren& children = parentRow.children();
238 Gtk::TreeNodeChildren* const pChildren = (Gtk::TreeNodeChildren* const) &children;
239 Gtk::TreeModel::iterator iterRow = m_treeStoreMacro->append(*pChildren);
240 #else
241 Gtk::TreeModel::iterator iterRow = m_treeStoreMacro->append(parentRow.children());
242 #endif
243 Gtk::TreeModel::Row row = *iterRow;
244 row[m_treeModelMacro.m_col_name] = gig_to_utf8(member.name());
245 row[m_treeModelMacro.m_col_type] = gig_to_utf8(member.type().asLongDescr());
246 row[m_treeModelMacro.m_col_uid] = object.uid();
247 row[m_treeModelMacro.m_col_allowTextEntry] = true;
248
249 if (object.type().isClass()) {
250 row[m_treeModelMacro.m_col_value] = "(class)";
251 row[m_treeModelMacro.m_col_editable] = false;
252 buildTreeView(row, object);
253 } else if (object.type().isEnum()) {
254 const char* key = gig::enumKey(
255 object.type().customTypeName(), m_macro.valueAsInt(object)
256 );
257 row[m_treeModelMacro.m_col_value] = key ? key : m_macro.valueAsString(object);
258 row[m_treeModelMacro.m_col_editable] = true;
259 const char** allKeys = gig::enumKeys(object.type().customTypeName());
260 if (allKeys) {
261 Glib::RefPtr<Gtk::ListStore> refOptions = createComboOptions(allKeys);
262 row[m_treeModelMacro.m_col_options] = refOptions;
263 }
264 } else if (object.type().isBool()) {
265 row[m_treeModelMacro.m_col_value] = _boolToStr( m_macro.valueAsBool(object) );
266 row[m_treeModelMacro.m_col_editable] = true;
267 Glib::RefPtr<Gtk::ListStore> refOptions = createComboOptions(_boolOptions);
268 row[m_treeModelMacro.m_col_options] = refOptions;
269 row[m_treeModelMacro.m_col_allowTextEntry] = false;
270 } else {
271 row[m_treeModelMacro.m_col_value] = m_macro.valueAsString(object);
272 row[m_treeModelMacro.m_col_editable] = true;
273 }
274 }
275 }
276
277 void MacroEditor::reloadTreeView() {
278 m_ignoreTreeViewValueChange = true;
279
280 m_treeStoreMacro->clear();
281
282 const Serialization::Object& rootObject = m_macro.rootObject();
283
284 Gtk::TreeModel::iterator iterRoot = m_treeStoreMacro->append();
285 Gtk::TreeModel::Row rowRoot = *iterRoot;
286 rowRoot[m_treeModelMacro.m_col_name] = "(Root)";
287 rowRoot[m_treeModelMacro.m_col_type] = gig_to_utf8(rootObject.type().asLongDescr());
288 rowRoot[m_treeModelMacro.m_col_value] = "";
289 rowRoot[m_treeModelMacro.m_col_uid] = rootObject.uid();
290 rowRoot[m_treeModelMacro.m_col_allowTextEntry] = false;
291 rowRoot[m_treeModelMacro.m_col_editable] = false;
292
293 buildTreeView(rowRoot, rootObject);
294
295 m_treeViewMacro.expand_all();
296
297 updateStatus();
298
299 m_ignoreTreeViewValueChange = false;
300 }
301
302 void MacroEditor::onTreeViewSelectionChanged() {
303 std::vector<Gtk::TreeModel::Path> v = m_treeViewMacro.get_selection()->get_selected_rows();
304 const bool bValidSelection = !v.empty();
305 m_deleteButton.set_sensitive(bValidSelection);
306 m_inverseDeleteButton.set_sensitive(bValidSelection);
307 }
308
309 // Cmd key on Mac, Ctrl key on all other OSs
310 static const guint primaryKeyL =
311 #if defined(__APPLE__)
312 GDK_KEY_Meta_L;
313 #else
314 GDK_KEY_Control_L;
315 #endif
316
317 static const guint primaryKeyR =
318 #if defined(__APPLE__)
319 GDK_KEY_Meta_R;
320 #else
321 GDK_KEY_Control_R;
322 #endif
323
324 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
325 bool MacroEditor::onKeyPressed(Gdk::EventKey& _key) {
326 GdkEventKey* key = _key.gobj();
327 #else
328 bool MacroEditor::onKeyPressed(GdkEventKey* key) {
329 #endif
330 //printf("key down 0x%x\n", key->keyval);
331 if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
332 m_altKeyDown = true;
333 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
334 m_primaryKeyDown = true;
335 return false;
336 }
337
338 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
339 bool MacroEditor::onKeyReleased(Gdk::EventKey& _key) {
340 GdkEventKey* key = _key.gobj();
341 #else
342 bool MacroEditor::onKeyReleased(GdkEventKey* key) {
343 #endif
344 //printf("key up 0x%x\n", key->keyval);
345 if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
346 m_altKeyDown = false;
347 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
348 m_primaryKeyDown = false;
349 return false;
350 }
351
352 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
353 bool MacroEditor::onMacroTreeViewKeyRelease(Gdk::EventKey& _key) {
354 GdkEventKey* key = _key.gobj();
355 #else
356 void MacroEditor::onMacroTreeViewKeyRelease(GdkEventKey* key) {
357 #endif
358 if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete) {
359 if (m_altKeyDown)
360 inverseDeleteSelectedRows();
361 else if (m_primaryKeyDown)
362 deleteSelectedRows();
363 }
364 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
365 return true;
366 #endif
367 }
368
369 void MacroEditor::onValueCellEdited(const Glib::ustring& sPath, const Glib::ustring& text) {
370 Gtk::TreePath path(sPath);
371 Gtk::TreeModel::iterator iter = m_treeStoreMacro->get_iter(path);
372 onMacroTreeViewRowValueChangedImpl(path, iter, text);
373 }
374
375 void MacroEditor::onMacroTreeViewRowValueChanged(const Gtk::TreeModel::Path& path,
376 const Gtk::TreeModel::iterator& iter)
377 {
378 if (!iter) return;
379 Gtk::TreeModel::Row row = *iter;
380 Glib::ustring value = row[m_treeModelMacro.m_col_value];
381 onMacroTreeViewRowValueChangedImpl(path, iter, value);
382 }
383
384 void MacroEditor::onMacroTreeViewRowValueChangedImpl(const Gtk::TreeModel::Path& path,
385 const Gtk::TreeModel::iterator& iter,
386 const Glib::ustring& value)
387 {
388 if (m_ignoreTreeViewValueChange) return;
389 if (!iter) return;
390 Gtk::TreeModel::Row row = *iter;
391 Serialization::UID uid = row[m_treeModelMacro.m_col_uid];
392 Serialization::String gigvalue(gig_from_utf8(value));
393 Serialization::Object& object = m_macro.objectByUID(uid);
394 std::string errorText;
395 try {
396 if (object.type().isEnum() &&
397 gig::enumKey(object.type().customTypeName(), gigvalue))
398 {
399 size_t iValue = gig::enumValue(gigvalue);
400 m_macro.setAutoValue(object, ToString(iValue));
401 // no auto correct here yet (due to numeric vs. textual values)
402 if (row[m_treeModelMacro.m_col_value] != value)
403 row[m_treeModelMacro.m_col_value] = value;
404 } else if (object.type().isBool()) {
405 m_macro.setAutoValue(object, gigvalue);
406 Serialization::String sBoolean = _boolToStr( m_macro.valueAsBool(object) );
407 // potentially auto correct (i.e. when type is bool, user entered '5' -> yields 'Yes')
408 if (row[m_treeModelMacro.m_col_value] != sBoolean)
409 row[m_treeModelMacro.m_col_value] = sBoolean;
410 } else {
411 m_macro.setAutoValue(object, gigvalue);
412 // potentially auto correct (i.e. when type is bool, user entered 5 -> yields 1)
413 if (row[m_treeModelMacro.m_col_value] != m_macro.valueAsString(object))
414 row[m_treeModelMacro.m_col_value] = m_macro.valueAsString(object);
415 }
416 updateStatus();
417 } catch (Serialization::Exception e) {
418 errorText = e.Message;
419 } catch (...) {
420 errorText = _("Unknown exception during object value change");
421 }
422 if (!errorText.empty()) {
423 Glib::ustring txt = _("Couldn't change value:\n") + errorText;
424 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
425 msg.run();
426 }
427 }
428
429 void MacroEditor::deleteSelectedRows() {
430 Glib::RefPtr<Gtk::TreeSelection> sel = m_treeViewMacro.get_selection();
431 std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
432 deleteRows(rows);
433 }
434
435 void MacroEditor::deleteRows(const std::vector<Gtk::TreeModel::Path>& rows) {
436 for (int r = rows.size() - 1; r >= 0; --r) {
437 Gtk::TreeModel::iterator it = m_treeStoreMacro->get_iter(rows[r]);
438 if (!it) continue;
439 Gtk::TreeModel::Row row = *it;
440 Serialization::UID uid = row[m_treeModelMacro.m_col_uid];
441 if (uid == m_macro.rootObject().uid()) continue; // prohibit deleting root object
442 Gtk::TreeModel::iterator itParent = row.parent();
443 if (!itParent) continue;
444 Gtk::TreeModel::Row rowParent = *itParent;
445 Serialization::UID uidParent = rowParent[m_treeModelMacro.m_col_uid];
446 //Serialization::Object& object = m_macro.objectByUID(uid);
447 Serialization::Object& parentObject = m_macro.objectByUID(uidParent);
448 const Serialization::Member& member = parentObject.memberByUID(uid);
449 m_macro.removeMember(parentObject, member);
450 //m_macro.remove(object);
451 }
452 reloadTreeView();
453 }
454
455 static bool _onEachTreeRow(const Gtk::TreeModel::Path& input, std::vector<Gtk::TreeModel::Path>* output) {
456 output->push_back(input);
457 return false; // continue walking the tree
458 }
459
460 void MacroEditor::inverseDeleteSelectedRows() {
461 // get all rows of tree view
462 std::vector<Gtk::TreeModel::Path> rows;
463 m_treeViewMacro.get_model()->foreach_path(
464 sigc::bind(
465 sigc::ptr_fun(&_onEachTreeRow),
466 &rows
467 )
468 );
469
470 // erase all entries from "rows" which are currently selected
471 std::vector<Gtk::TreeModel::Path> vSelected = m_treeViewMacro.get_selection()->get_selected_rows();
472 for (int i = rows.size() - 1; i >= 0; --i) {
473 bool bIsSelected = std::find(vSelected.begin(), vSelected.end(),
474 rows[i]) != vSelected.end();
475 if (bIsSelected)
476 rows.erase(rows.begin() + i);
477 }
478
479 // delete those 'inverse' selected rows
480 deleteRows(rows);
481 }
482
483 void MacroEditor::updateStatus() {
484 m_applyButton.set_sensitive(isModified());
485 updateStatusBar();
486 }
487
488 void MacroEditor::updateStatusBar() {
489 // update status text
490 std::string txt;
491 m_statusLabel.set_markup(txt);
492 }
493
494 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION > 91 || (GTKMM_MINOR_VERSION == 91 && GTKMM_MICRO_VERSION >= 2))) // GTKMM >= 3.91.2
495 bool MacroEditor::onWindowDelete(Gdk::Event& e) {
496 return onWindowDeleteP(NULL);
497 }
498 #endif
499
500 bool MacroEditor::onWindowDeleteP(GdkEventAny* /*e*/) {
501 //printf("onWindowDelete\n");
502
503 if (!isModified()) return false; // propagate event further (which will close this window)
504
505 //gchar* msg = g_strdup_printf(_("Apply changes to macro \"%s\" before closing?"),
506 // m_macroOriginal->Name.c_str());
507 gchar* msg = g_strdup(_("Apply changes to macro before closing?"));
508 Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
509 g_free(msg);
510 dialog.set_secondary_text(_("If you close without applying, your changes will be lost."));
511 dialog.add_button(_("Close _Without Applying"), Gtk::RESPONSE_NO);
512 dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
513 dialog.add_button(_("_Apply"), Gtk::RESPONSE_YES);
514 dialog.set_default_response(Gtk::RESPONSE_YES);
515 int response = dialog.run();
516 dialog.hide();
517
518 // user decided to close macro editor without saving
519 if (response == Gtk::RESPONSE_NO)
520 return false; // propagate event further (which will close this window)
521
522 // user cancelled dialog, thus don't close macro editor
523 if (response == Gtk::RESPONSE_CANCEL) {
524 show();
525 return true; // drop event (prevents closing this window)
526 }
527
528 // user wants to apply the changes, afterwards close window
529 if (response == Gtk::RESPONSE_YES) {
530 onButtonApply();
531 return false; // propagate event further (which will close this window)
532 }
533
534 // should never ever make it to this point actually
535 return false;
536 }
537
538 bool MacroEditor::isModified() const {
539 return m_macro.isModified();
540 }
541
542 void MacroEditor::onButtonCancel() {
543 bool dropEvent = onWindowDeleteP(NULL);
544 if (dropEvent) return;
545 hide();
546 }
547
548 void MacroEditor::onButtonApply() {
549 std::string errorText;
550 try {
551 // enforce re-encoding the abstract object model and resetting the
552 // 'modified' state
553 m_macro.rawData();
554 // replace actual effective Archive object which is effectively used
555 // for macro apply operations
556 *m_macroOriginal = m_macro;
557 } catch (Serialization::Exception e) {
558 errorText = e.Message;
559 } catch (...) {
560 errorText = _("Unknown exception while applying macro changes");
561 }
562 if (!errorText.empty()) {
563 Glib::ustring txt = _("Couldn't apply macro changes:\n") + errorText;
564 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
565 msg.run();
566 }
567 updateStatus();
568 m_changes_applied.emit();
569 }
570
571 void MacroEditor::onWindowHide() {
572 delete this; // this is the end, my friend
573 }

  ViewVC Help
Powered by ViewVC