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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3456 - (hide 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 schoenebeck 3151 /*
2 persson 3456 Copyright (c) MMXVII - MMXIX Christian Schoenebeck
3 schoenebeck 3151
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 schoenebeck 3155 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 schoenebeck 3151 m_applyButton(_("_Apply"), true),
18 schoenebeck 3155 m_cancelButton(_("_Cancel"), true),
19 schoenebeck 3170 m_altKeyDown(false),
20     m_primaryKeyDown(false)
21 schoenebeck 3151 {
22     add(m_vbox);
23    
24 schoenebeck 3225 if (!Settings::singleton()->autoRestoreWindowDimension) {
25     set_default_size(800, 600);
26     set_position(Gtk::WIN_POS_MOUSE);
27     }
28 schoenebeck 3151
29 schoenebeck 3364 #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 schoenebeck 3184 m_labelIntro.set_padding(10, 10);
34 schoenebeck 3364 #endif
35 schoenebeck 3184 #if GTKMM_MAJOR_VERSION >= 3
36     m_labelIntro.set_line_wrap();
37     #endif
38     m_labelIntro.set_text(
39 schoenebeck 3162 _("A macro is a list of parameters and corresponding values which "
40     "should be applied to the instrument editor when the macro is "
41 schoenebeck 3184 "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 schoenebeck 3162 );
47 schoenebeck 3184 m_vbox.pack_start(m_labelIntro, Gtk::PACK_SHRINK);
48 schoenebeck 3162
49 schoenebeck 3151 // 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 schoenebeck 3170 //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 schoenebeck 3154 {
65 schoenebeck 3170 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 schoenebeck 3187 column->add_attribute(m_valueCellRenderer.property_has_entry(),
70     m_treeModelMacro.m_col_allowTextEntry);
71 schoenebeck 3170 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 schoenebeck 3154 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 schoenebeck 3151 m_treeViewMacro.set_headers_visible(true);
88 schoenebeck 3154 m_treeViewMacro.get_selection()->signal_changed().connect(
89     sigc::mem_fun(*this, &MacroEditor::onTreeViewSelectionChanged)
90     );
91 schoenebeck 3364 #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 schoenebeck 3154 m_treeViewMacro.signal_key_release_event().connect_notify(
95 schoenebeck 3364 #endif
96 schoenebeck 3154 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 schoenebeck 3151
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 schoenebeck 3154 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 schoenebeck 3151 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 schoenebeck 3364 #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 schoenebeck 3151 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 schoenebeck 3364 #if HAS_GTKMM_SHOW_ALL_CHILDREN
132 schoenebeck 3151 m_statusHBox.show_all_children();
133 schoenebeck 3364 #endif
134 schoenebeck 3151
135 schoenebeck 3154 m_footerHBox.pack_start(m_buttonBoxL, Gtk::PACK_SHRINK);
136 schoenebeck 3151 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 schoenebeck 3154 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 schoenebeck 3151 signal_hide().connect(
158     sigc::mem_fun(*this, &MacroEditor::onWindowHide)
159     );
160    
161     signal_delete_event().connect(
162 schoenebeck 3364 #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 schoenebeck 3151 sigc::mem_fun(*this, &MacroEditor::onWindowDelete)
164 schoenebeck 3364 #else
165     sigc::mem_fun(*this, &MacroEditor::onWindowDeleteP)
166     #endif
167 schoenebeck 3151 );
168    
169 schoenebeck 3155 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 schoenebeck 3184 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 schoenebeck 3364 #if HAS_GTKMM_SHOW_ALL_CHILDREN
180 schoenebeck 3151 show_all_children();
181 schoenebeck 3364 #endif
182 schoenebeck 3151 updateStatus();
183     }
184    
185     MacroEditor::~MacroEditor() {
186     printf("MacroEditor destruct\n");
187     }
188    
189 schoenebeck 3162 void MacroEditor::setMacro(Serialization::Archive* macro, bool isClipboard) {
190 schoenebeck 3151 m_macroOriginal = macro;
191     if (!macro) {
192     set_title(_("No Macro"));
193     return;
194     }
195    
196 schoenebeck 3162 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 schoenebeck 3151
205     // copy for non-destructive editing
206     m_macro = *macro;
207    
208     reloadTreeView();
209     }
210    
211 schoenebeck 3162 sigc::signal<void>& MacroEditor::signal_changes_applied() {
212     return m_changes_applied;
213     }
214    
215 schoenebeck 3170 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 schoenebeck 3187 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 schoenebeck 3151 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 schoenebeck 3364
235 schoenebeck 3450 #if GTKMM_MAJOR_VERSION > 3 || (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION > 24)
236 schoenebeck 3364 //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 schoenebeck 3151 Gtk::TreeModel::iterator iterRow = m_treeStoreMacro->append(parentRow.children());
242 schoenebeck 3364 #endif
243 schoenebeck 3151 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 schoenebeck 3187 row[m_treeModelMacro.m_col_allowTextEntry] = true;
248 schoenebeck 3170
249 schoenebeck 3151 if (object.type().isClass()) {
250     row[m_treeModelMacro.m_col_value] = "(class)";
251 schoenebeck 3170 row[m_treeModelMacro.m_col_editable] = false;
252 schoenebeck 3151 buildTreeView(row, object);
253 schoenebeck 3170 } 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 schoenebeck 3187 } 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 schoenebeck 3151 } else {
271     row[m_treeModelMacro.m_col_value] = m_macro.valueAsString(object);
272 schoenebeck 3170 row[m_treeModelMacro.m_col_editable] = true;
273 schoenebeck 3151 }
274     }
275     }
276    
277     void MacroEditor::reloadTreeView() {
278 schoenebeck 3154 m_ignoreTreeViewValueChange = true;
279    
280 schoenebeck 3151 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 schoenebeck 3170 rowRoot[m_treeModelMacro.m_col_allowTextEntry] = false;
291     rowRoot[m_treeModelMacro.m_col_editable] = false;
292 schoenebeck 3151
293     buildTreeView(rowRoot, rootObject);
294    
295     m_treeViewMacro.expand_all();
296    
297     updateStatus();
298 schoenebeck 3154
299     m_ignoreTreeViewValueChange = false;
300 schoenebeck 3151 }
301    
302 schoenebeck 3154 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 schoenebeck 3170 // 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 schoenebeck 3364 #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 schoenebeck 3155 bool MacroEditor::onKeyPressed(GdkEventKey* key) {
329 schoenebeck 3364 #endif
330 schoenebeck 3155 //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 schoenebeck 3170 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
334     m_primaryKeyDown = true;
335 schoenebeck 3155 return false;
336     }
337    
338 schoenebeck 3364 #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 schoenebeck 3155 bool MacroEditor::onKeyReleased(GdkEventKey* key) {
343 schoenebeck 3364 #endif
344 schoenebeck 3155 //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 schoenebeck 3170 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
348     m_primaryKeyDown = false;
349 schoenebeck 3155 return false;
350     }
351    
352 schoenebeck 3364 #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 schoenebeck 3154 void MacroEditor::onMacroTreeViewKeyRelease(GdkEventKey* key) {
357 schoenebeck 3364 #endif
358 schoenebeck 3155 if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete) {
359     if (m_altKeyDown)
360     inverseDeleteSelectedRows();
361 schoenebeck 3170 else if (m_primaryKeyDown)
362 schoenebeck 3155 deleteSelectedRows();
363     }
364 schoenebeck 3364 #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 schoenebeck 3154 }
368    
369 schoenebeck 3170 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 schoenebeck 3154 void MacroEditor::onMacroTreeViewRowValueChanged(const Gtk::TreeModel::Path& path,
376     const Gtk::TreeModel::iterator& iter)
377     {
378 schoenebeck 3170 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 schoenebeck 3154 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 schoenebeck 3170 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 schoenebeck 3187 } 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 schoenebeck 3170 } 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 schoenebeck 3154 } 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 schoenebeck 3155 deleteRows(rows);
433     }
434    
435     void MacroEditor::deleteRows(const std::vector<Gtk::TreeModel::Path>& rows) {
436 schoenebeck 3154 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 schoenebeck 3155 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 schoenebeck 3154 void MacroEditor::inverseDeleteSelectedRows() {
461 schoenebeck 3155 // 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 schoenebeck 3154 }
482    
483 schoenebeck 3151 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 schoenebeck 3364 #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 schoenebeck 3151 //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 persson 3456 gchar* msg = g_strdup(_("Apply changes to macro before closing?"));
508 schoenebeck 3151 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 schoenebeck 3364 bool dropEvent = onWindowDeleteP(NULL);
544 schoenebeck 3151 if (dropEvent) return;
545     hide();
546     }
547    
548     void MacroEditor::onButtonApply() {
549 schoenebeck 3155 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 schoenebeck 3162 m_changes_applied.emit();
569 schoenebeck 3151 }
570    
571     void MacroEditor::onWindowHide() {
572     delete this; // this is the end, my friend
573     }

  ViewVC Help
Powered by ViewVC