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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3162 - (hide annotations) (download)
Tue May 9 14:35:23 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 22768 byte(s)
* Macros Setup: Implemented reordering macros by "Up" and
  "Down" buttons (and accordingly also altering the
  F1 ... F12 acceleration keys they are assigned to).
* Macros Setup: Implemented calling Macro Editor from
  this macro setup dialog by hitting "Edit" button.
* Macros Setup: Implemented editing comment on macros.
* Macros Setup: Enabled various icons.
* Bumped version (1.0.0.svn41).

1 schoenebeck 3157 /*
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 "MacrosSetup.h"
9     #include "global.h"
10     #include <assert.h>
11     #include <set>
12 schoenebeck 3160 #include <math.h>
13     #include <gtkmm/stock.h>
14 schoenebeck 3162 #include "MacroEditor.h"
15 schoenebeck 3157
16     MacrosSetup::MacrosSetup() :
17 schoenebeck 3160 m_modified(false),
18     m_clipboardContent(NULL),
19     m_addFromClipboardButton(" " + Glib::ustring(_("From Clipboard")) + " " + UNICODE_PRIMARY_KEY_SYMBOL + "B"),
20     m_addFromSelectionButton(" " + Glib::ustring(_("From Selection")) + " " + UNICODE_PRIMARY_KEY_SYMBOL + "S"),
21 schoenebeck 3162 m_buttonUp(Gtk::Stock::GO_UP),
22     m_buttonDown(Gtk::Stock::GO_DOWN),
23     m_buttonEdit(Gtk::Stock::EDIT),
24 schoenebeck 3157 m_statusLabel("", Gtk::ALIGN_START),
25 schoenebeck 3162 m_labelComment(_("Comment"), Gtk::ALIGN_START),
26     m_deleteButton(" " + Glib::ustring(_("Delete")) + " " + UNICODE_PRIMARY_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
27     m_inverseDeleteButton(" " + Glib::ustring(_("Inverse Delete")) + " " + UNICODE_ALT_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
28     m_applyButton(Gtk::Stock::APPLY),
29     m_cancelButton(Gtk::Stock::CANCEL),
30 schoenebeck 3160 m_altKeyDown(false),
31     m_primaryKeyDown(false)
32 schoenebeck 3157 {
33     add(m_vbox);
34    
35     set_title(_("Setup Macros"));
36    
37 schoenebeck 3162 set_default_size(680, 500);
38 schoenebeck 3157
39 schoenebeck 3160 m_addFromClipboardButton.set_image(
40     *new Gtk::Image(Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)
41     );
42     m_addFromSelectionButton.set_image(
43     *new Gtk::Image(Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)
44     );
45 schoenebeck 3162 m_deleteButton.set_image(
46     *new Gtk::Image(Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)
47     );
48     m_inverseDeleteButton.set_image(
49     *new Gtk::Image(Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)
50     );
51 schoenebeck 3160 m_addFromClipboardButton.set_tooltip_text(_("Create a new macro from the content currently available on the clipboard."));
52     m_addFromSelectionButton.set_tooltip_text(_("Create a new macro from the currently selected dimension region's parameters currently shown on the main window."));
53 schoenebeck 3162 m_addHBox.pack_start(m_addFromClipboardButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
54     m_addHBox.pack_start(m_addFromSelectionButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
55 schoenebeck 3160 m_vbox.pack_start(m_addHBox, Gtk::PACK_SHRINK);
56    
57 schoenebeck 3162 m_vbox.pack_start(m_mainHBox);
58     m_vbox.set_spacing(5);
59    
60 schoenebeck 3157 // create Macro list treeview (including its data model)
61     m_treeStoreMacros = MacroListTreeStore::create(m_treeModelMacros);
62     m_treeViewMacros.set_model(m_treeStoreMacros);
63     m_treeViewMacros.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
64     //m_treeViewMacro.set_tooltip_text(_(""));
65     m_treeViewMacros.append_column(_("Key"), m_treeModelMacros.m_col_key);
66 schoenebeck 3162 m_treeViewMacros.append_column_editable(_("Macro Name"), m_treeModelMacros.m_col_name);
67 schoenebeck 3157 m_treeViewMacros.append_column(_("Created"), m_treeModelMacros.m_col_created);
68     m_treeViewMacros.append_column(_("Modified"), m_treeModelMacros.m_col_modified);
69     m_treeViewMacros.set_tooltip_column(m_treeModelMacros.m_col_comment.index());
70     // make all rows gray text, except of "Name" column
71     for (int i = 0; i <= 3; ++i) {
72     if (i == m_treeModelMacros.m_col_name.index())
73     continue;
74     Gtk::TreeViewColumn* column = m_treeViewMacros.get_column(i);
75     Gtk::CellRendererText* cellrenderer =
76     dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
77     cellrenderer->property_foreground().set_value("#bababa");
78     }
79     /*{
80     Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(0);
81     Gtk::CellRendererText* cellrenderer =
82     dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
83     column->add_attribute(
84     cellrenderer->property_foreground(), m_SamplesModel.m_color
85     );
86     }*/
87     /*{
88     Gtk::TreeViewColumn* column = m_treeViewMacro.get_column(1);
89     Gtk::CellRendererText* cellrenderer =
90     dynamic_cast<Gtk::CellRendererText*>(column->get_first_cell());
91     column->add_attribute(
92     cellrenderer->property_foreground(), m_SamplesModel.m_color
93     );
94     }*/
95     m_treeViewMacros.set_headers_visible(true);
96     m_treeViewMacros.get_selection()->signal_changed().connect(
97     sigc::mem_fun(*this, &MacrosSetup::onTreeViewSelectionChanged)
98     );
99 schoenebeck 3160 m_treeViewMacros.signal_key_release_event().connect_notify(
100 schoenebeck 3157 sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewKeyRelease)
101 schoenebeck 3160 );
102 schoenebeck 3157 m_treeStoreMacros->signal_row_changed().connect(
103     sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewRowValueChanged)
104     );
105     m_ignoreTreeViewValueChange = false;
106 schoenebeck 3162 m_ignoreCommentTextViewChange = false;
107 schoenebeck 3157
108     m_scrolledWindow.add(m_treeViewMacros);
109     m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
110 schoenebeck 3162 m_mainHBox.pack_start(m_scrolledWindow);
111 schoenebeck 3157
112 schoenebeck 3162 m_rvbox.set_spacing(5);
113    
114     m_mainHBox.pack_start(m_rvbox, Gtk::PACK_SHRINK);
115     m_mainHBox.set_spacing(5),
116     m_rvbox.set_spacing(5);
117     m_rvbox.pack_start(m_detailsButtonBox, Gtk::PACK_SHRINK);
118    
119     //m_textViewComment.set_left_margin(3);
120     //m_textViewComment.set_right_margin(3);
121     m_textViewComment.set_indent(2);
122     m_scrolledWindowComment.add(m_textViewComment);
123     m_scrolledWindowComment.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
124     m_labelComment.set_markup(
125     "<b>" + m_labelComment.get_text() + "</b>"
126     );
127     m_rvbox.pack_start(m_labelComment, Gtk::PACK_SHRINK);
128     m_rvbox.pack_start(m_scrolledWindowComment);
129    
130     m_detailsButtonBox.pack_start(m_buttonUp);
131     m_detailsButtonBox.pack_start(m_buttonDown);
132     m_detailsButtonBox.pack_start(m_buttonEdit);
133    
134 schoenebeck 3157 m_buttonBoxL.set_layout(Gtk::BUTTONBOX_START);
135     m_buttonBoxL.pack_start(m_deleteButton);
136     m_buttonBoxL.pack_start(m_inverseDeleteButton);
137     m_deleteButton.set_sensitive(false);
138     m_inverseDeleteButton.set_sensitive(false);
139    
140     m_buttonBox.set_layout(Gtk::BUTTONBOX_END);
141     m_buttonBox.pack_start(m_applyButton);
142     m_buttonBox.pack_start(m_cancelButton);
143     m_applyButton.set_can_default();
144     m_applyButton.set_sensitive(false);
145     m_applyButton.grab_focus();
146    
147     #if GTKMM_MAJOR_VERSION >= 3
148     m_statusLabel.set_margin_left(6);
149     m_statusLabel.set_margin_right(6);
150     #else
151     m_statusHBox.set_spacing(6);
152     #endif
153    
154     m_statusHBox.pack_start(m_statusLabel);
155     m_statusHBox.show_all_children();
156    
157     m_footerHBox.pack_start(m_buttonBoxL, Gtk::PACK_SHRINK);
158     m_footerHBox.pack_start(m_statusHBox);
159     m_footerHBox.pack_start(m_buttonBox, Gtk::PACK_SHRINK);
160    
161     m_vbox.pack_start(m_footerHBox, Gtk::PACK_SHRINK);
162    
163 schoenebeck 3160 m_addFromClipboardButton.signal_clicked().connect(
164     sigc::mem_fun(*this, &MacrosSetup::onButtonAddFromClipboard)
165     );
166    
167     m_addFromSelectionButton.signal_clicked().connect(
168     sigc::mem_fun(*this, &MacrosSetup::onButtonAddFromSelection)
169     );
170    
171 schoenebeck 3162 m_buttonUp.signal_clicked().connect(
172     sigc::mem_fun(*this, &MacrosSetup::onButtonUp)
173     );
174    
175     m_buttonDown.signal_clicked().connect(
176     sigc::mem_fun(*this, &MacrosSetup::onButtonDown)
177     );
178    
179     m_buttonEdit.signal_clicked().connect(
180     sigc::mem_fun(*this, &MacrosSetup::onButtonEdit)
181     );
182    
183     m_textViewComment.get_buffer()->signal_changed().connect(
184     sigc::mem_fun(*this, &MacrosSetup::onCommentTextViewChanged)
185     );
186    
187 schoenebeck 3157 m_applyButton.signal_clicked().connect(
188     sigc::mem_fun(*this, &MacrosSetup::onButtonApply)
189     );
190    
191     m_cancelButton.signal_clicked().connect(
192     sigc::mem_fun(*this, &MacrosSetup::onButtonCancel)
193     );
194    
195     m_deleteButton.signal_clicked().connect(
196     sigc::mem_fun(*this, &MacrosSetup::deleteSelectedRows)
197     );
198    
199     m_inverseDeleteButton.signal_clicked().connect(
200     sigc::mem_fun(*this, &MacrosSetup::inverseDeleteSelectedRows)
201     );
202    
203     signal_hide().connect(
204     sigc::mem_fun(*this, &MacrosSetup::onWindowHide)
205     );
206    
207     signal_delete_event().connect(
208     sigc::mem_fun(*this, &MacrosSetup::onWindowDelete)
209     );
210    
211     signal_key_press_event().connect(
212     sigc::mem_fun(*this, &MacrosSetup::onKeyPressed)
213     );
214     signal_key_release_event().connect(
215     sigc::mem_fun(*this, &MacrosSetup::onKeyReleased)
216     );
217    
218     show_all_children();
219     updateStatus();
220     }
221    
222     MacrosSetup::~MacrosSetup() {
223     printf("MacrosSetup destruct\n");
224     }
225    
226 schoenebeck 3160 void MacrosSetup::setMacros(const std::vector<Serialization::Archive>& macros,
227     Serialization::Archive* pClipboardContent,
228     gig::DimensionRegion* pSelectedDimRgn)
229     {
230 schoenebeck 3157 // copy for non-destructive editing
231     m_macros = macros;
232    
233 schoenebeck 3160 m_clipboardContent = pClipboardContent;
234     m_selectedDimRgn = pSelectedDimRgn;
235    
236 schoenebeck 3157 reloadTreeView();
237     }
238    
239 schoenebeck 3160 void MacrosSetup::onButtonAddFromClipboard() {
240     printf("+fromClipboard\n");
241     if (!m_clipboardContent) return;
242     if (!m_clipboardContent->rootObject()) return;
243     m_macros.push_back(*m_clipboardContent);
244     m_modified = true;
245     reloadTreeView();
246     }
247    
248     void MacrosSetup::onButtonAddFromSelection() {
249     printf("+fromSelection\n");
250     if (!m_selectedDimRgn) return;
251     std::string errorText;
252     try {
253     Serialization::Archive archive;
254     archive.serialize(m_selectedDimRgn);
255     //archive.setName("Unnamed Macro");
256     m_macros.push_back(archive);
257     m_modified = true;
258     reloadTreeView();
259     } catch (Serialization::Exception e) {
260     errorText = e.Message;
261     } catch (...) {
262     errorText = _("Unknown exception while creating macro");
263     }
264     if (!errorText.empty()) {
265     Glib::ustring txt = _("Couldn't create macro:\n") + errorText;
266     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
267     msg.run();
268     }
269     }
270    
271 schoenebeck 3162 void MacrosSetup::moveByDir(int d) {
272     if (d < -1 || d > 1) return;
273     int index = getSelectedMacroIndex();
274     if (index < 0) return;
275     if (d == -1 && index == 0) return;
276     if (d == +1 && index >= m_macros.size() - 1) return;
277    
278     // swap macros
279     std::swap(m_macros[index + d], m_macros[index]);
280    
281     // swap tree view rows
282     Gtk::TreePath p1(ToString(index + d));
283     Gtk::TreePath p2(ToString(index));
284     Gtk::TreeModel::iterator it1 = m_treeStoreMacros->get_iter(p1);
285     Gtk::TreeModel::iterator it2 = m_treeStoreMacros->get_iter(p2);
286     m_treeStoreMacros->iter_swap(it1, it2);
287     int idx1 = (*it1)[m_treeModelMacros.m_col_index];
288     int idx2 = (*it2)[m_treeModelMacros.m_col_index];
289     (*it1)[m_treeModelMacros.m_col_index] = idx2;
290     (*it2)[m_treeModelMacros.m_col_index] = idx1;
291     Glib::ustring s1 = (*it1)[m_treeModelMacros.m_col_key];
292     Glib::ustring s2 = (*it2)[m_treeModelMacros.m_col_key];
293     (*it1)[m_treeModelMacros.m_col_key] = s2;
294     (*it2)[m_treeModelMacros.m_col_key] = s1;
295    
296     m_modified = true;
297     }
298    
299     void MacrosSetup::onButtonUp() {
300     moveByDir(-1);
301     }
302    
303     void MacrosSetup::onButtonDown() {
304     moveByDir(+1);
305     }
306    
307     void MacrosSetup::onButtonEdit() {
308     Serialization::Archive* macro = getSelectedMacro();
309     if (!macro) return;
310    
311     m_modifiedBeforeMacroEditor = isModified();
312    
313     MacroEditor* editor = new MacroEditor();
314     editor->setMacro(macro, false);
315     editor->signal_changes_applied().connect(
316     sigc::mem_fun(*this, &MacrosSetup::onMacroEditorAppliedChanges)
317     );
318     editor->show();
319     }
320    
321     void MacrosSetup::onMacroEditorAppliedChanges() {
322     // so that the user does not need to click on a Apply buttons twice
323     if (!m_modifiedBeforeMacroEditor)
324     onButtonApply();
325     updateStatus();
326     }
327    
328     void MacrosSetup::onCommentTextViewChanged() {
329     if (m_ignoreCommentTextViewChange) return;
330     //printf("textChanged\n");
331     Serialization::Archive* macro = getSelectedMacro();
332     if (!macro) return;
333     macro->setComment(
334     m_textViewComment.get_buffer()->get_text()
335     );
336     updateStatus();
337     }
338    
339     int MacrosSetup::getSelectedMacroIndex() const {
340     std::vector<Gtk::TreeModel::Path> v = m_treeViewMacros.get_selection()->get_selected_rows();
341     if (v.empty()) return -1;
342     Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(v[0]);
343     if (!it) return -1;
344     const Gtk::TreeModel::Row& row = *it;
345     int index = row[m_treeModelMacros.m_col_index];
346     if (index < 0 || index >= m_macros.size()) return -1;
347     return index;
348     }
349    
350     Serialization::Archive* MacrosSetup::getSelectedMacro() {
351     int index = getSelectedMacroIndex();
352     if (index < 0) return NULL;
353     return &m_macros[index];
354     }
355    
356 schoenebeck 3157 static Glib::ustring indexToAccKey(uint index) {
357     if (index >= 12) return "";
358     return "F" + ToString(index+1);
359     }
360    
361 schoenebeck 3160 static int daysAgo(const tm& t) {
362     time_t now;
363     time(&now);
364     tm* pNow = localtime(&now);
365     if (!pNow) return 0;
366     if (pNow->tm_year == t.tm_year &&
367     pNow->tm_mon == t.tm_mon &&
368     pNow->tm_mday == t.tm_mday) return 0;
369     time_t past = mktime((tm*)&t);
370 schoenebeck 3161 return ceil(difftime(now, past) / 60.0 / 60.0 / 24.0);
371 schoenebeck 3160 }
372    
373 schoenebeck 3157 static Glib::ustring humanShortStr(const tm& t) {
374 schoenebeck 3160 int iDaysAgo = daysAgo(t);
375 schoenebeck 3157 char buf[70];
376 schoenebeck 3160 if (iDaysAgo == 0) {
377 schoenebeck 3157 // C-Time specification for a time somewhere today (see 'man strftime()').
378     if (strftime(buf, sizeof buf, _("%R"), &t))
379     return buf;
380 schoenebeck 3160 } else if (iDaysAgo == 1) {
381 schoenebeck 3157 // C-Time specification for a time somewhere yesterday (see 'man strftime()').
382     if (strftime(buf, sizeof buf, _("Yesterday %R"), &t))
383     return buf;
384 schoenebeck 3160 } else if (iDaysAgo == 2) {
385 schoenebeck 3157 // C-Time specification for a time somewhere 2 days ago (see 'man strftime()').
386     if (strftime(buf, sizeof buf, _("2 days ago %R"), &t))
387     return buf;
388     } else {
389     // C-Time specification for a time far more than 2 days ago (see 'man strftime()').
390     if (strftime(buf, sizeof buf, "%d %b %Y", &t))
391     return buf;
392     }
393     return "";
394     }
395    
396     void MacrosSetup::reloadTreeView() {
397     m_ignoreTreeViewValueChange = true;
398    
399     m_treeStoreMacros->clear();
400    
401     for (int iMacro = 0; iMacro < m_macros.size(); ++iMacro) {
402     const Serialization::Archive& macro = m_macros[iMacro];
403    
404     Gtk::TreeModel::iterator iter = m_treeStoreMacros->append();
405     Gtk::TreeModel::Row row = *iter;
406     row[m_treeModelMacros.m_col_key] = indexToAccKey(iMacro);
407 schoenebeck 3160 row[m_treeModelMacros.m_col_name] = macro.name().empty() ? _("Unnamed Macro") : gig_to_utf8(macro.name());
408     row[m_treeModelMacros.m_col_comment] = macro.comment().empty() ? _("No comment assigned yet.") : gig_to_utf8(macro.comment());
409 schoenebeck 3157 row[m_treeModelMacros.m_col_created] = humanShortStr(macro.dateTimeCreated());
410     row[m_treeModelMacros.m_col_modified] = humanShortStr(macro.dateTimeModified());
411     row[m_treeModelMacros.m_col_index] = iMacro;
412     }
413    
414     m_treeViewMacros.expand_all();
415    
416     updateStatus();
417    
418     m_ignoreTreeViewValueChange = false;
419     }
420    
421     void MacrosSetup::onTreeViewSelectionChanged() {
422     std::vector<Gtk::TreeModel::Path> v = m_treeViewMacros.get_selection()->get_selected_rows();
423     const bool bValidSelection = !v.empty();
424     m_deleteButton.set_sensitive(bValidSelection);
425     m_inverseDeleteButton.set_sensitive(bValidSelection);
426 schoenebeck 3162 m_buttonEdit.set_sensitive(bValidSelection);
427    
428     // update comment text view
429     std::string sComment;
430     Serialization::Archive* macro = getSelectedMacro();
431     if (macro)
432     sComment = macro->comment();
433     m_ignoreCommentTextViewChange = true;
434     m_textViewComment.get_buffer()->set_text(sComment);
435     m_ignoreCommentTextViewChange = false;
436     m_textViewComment.set_sensitive(bValidSelection);
437 schoenebeck 3157 }
438    
439 schoenebeck 3160 // Cmd key on Mac, Ctrl key on all other OSs
440     static const guint primaryKeyL =
441     #if defined(__APPLE__)
442     GDK_KEY_Meta_L;
443     #else
444     GDK_KEY_Control_L;
445     #endif
446    
447     static const guint primaryKeyR =
448     #if defined(__APPLE__)
449     GDK_KEY_Meta_R;
450     #else
451     GDK_KEY_Control_R;
452     #endif
453    
454 schoenebeck 3157 bool MacrosSetup::onKeyPressed(GdkEventKey* key) {
455     //printf("key down 0x%x\n", key->keyval);
456     if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
457     m_altKeyDown = true;
458 schoenebeck 3160 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
459     m_primaryKeyDown = true;
460 schoenebeck 3157 return false;
461     }
462    
463     bool MacrosSetup::onKeyReleased(GdkEventKey* key) {
464     //printf("key up 0x%x\n", key->keyval);
465     if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
466     m_altKeyDown = false;
467 schoenebeck 3160 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
468     m_primaryKeyDown = false;
469     if (m_primaryKeyDown && key->keyval == GDK_KEY_b)
470     onButtonAddFromClipboard();
471     if (m_primaryKeyDown && key->keyval == GDK_KEY_s)
472     onButtonAddFromSelection();
473 schoenebeck 3157 return false;
474     }
475    
476     void MacrosSetup::onMacroTreeViewKeyRelease(GdkEventKey* key) {
477     if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete) {
478     if (m_altKeyDown)
479     inverseDeleteSelectedRows();
480 schoenebeck 3160 else if (m_primaryKeyDown)
481 schoenebeck 3157 deleteSelectedRows();
482     }
483     }
484    
485     void MacrosSetup::onMacroTreeViewRowValueChanged(const Gtk::TreeModel::Path& path,
486     const Gtk::TreeModel::iterator& iter)
487     {
488     if (m_ignoreTreeViewValueChange) return;
489     if (!iter) return;
490     Gtk::TreeModel::Row row = *iter;
491     Glib::ustring name = row[m_treeModelMacros.m_col_name];
492     int index = row[m_treeModelMacros.m_col_index];
493     m_macros[index].setName(name);
494     //reloadTreeView();
495 schoenebeck 3160 m_modified = true;
496     updateStatus();
497 schoenebeck 3157 }
498    
499     void MacrosSetup::deleteSelectedRows() {
500     Glib::RefPtr<Gtk::TreeSelection> sel = m_treeViewMacros.get_selection();
501     std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
502     deleteRows(rows);
503     }
504    
505     void MacrosSetup::deleteRows(const std::vector<Gtk::TreeModel::Path>& rows) {
506 schoenebeck 3160 m_modified = !rows.empty();
507 schoenebeck 3157 std::set<int> macros;
508     for (int r = rows.size() - 1; r >= 0; --r) {
509     Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(rows[r]);
510     if (!it) continue;
511     Gtk::TreeModel::Row row = *it;
512     macros.insert(
513     row[m_treeModelMacros.m_col_index]
514     );
515     }
516     for (std::set<int>::const_reverse_iterator it = macros.rbegin();
517     it != macros.rend(); ++it)
518     {
519     m_macros.erase(m_macros.begin() + *it);
520     }
521     reloadTreeView();
522     }
523    
524     static bool _onEachTreeRow(const Gtk::TreeModel::Path& input, std::vector<Gtk::TreeModel::Path>* output) {
525     output->push_back(input);
526     return false; // continue walking the tree
527     }
528    
529     void MacrosSetup::inverseDeleteSelectedRows() {
530     // get all rows of tree view
531     std::vector<Gtk::TreeModel::Path> rows;
532     m_treeViewMacros.get_model()->foreach_path(
533     sigc::bind(
534     sigc::ptr_fun(&_onEachTreeRow),
535     &rows
536     )
537     );
538    
539     // erase all entries from "rows" which are currently selected
540     std::vector<Gtk::TreeModel::Path> vSelected = m_treeViewMacros.get_selection()->get_selected_rows();
541     for (int i = rows.size() - 1; i >= 0; --i) {
542     bool bIsSelected = std::find(vSelected.begin(), vSelected.end(),
543     rows[i]) != vSelected.end();
544     if (bIsSelected)
545     rows.erase(rows.begin() + i);
546     }
547    
548     // delete those 'inverse' selected rows
549     deleteRows(rows);
550     }
551    
552     void MacrosSetup::updateStatus() {
553 schoenebeck 3162 bool bValidSelection = !m_treeViewMacros.get_selection()->get_selected_rows().empty();
554 schoenebeck 3160 m_addFromClipboardButton.set_sensitive(
555     m_clipboardContent && m_clipboardContent->rootObject()
556     );
557     m_addFromSelectionButton.set_sensitive(m_selectedDimRgn);
558 schoenebeck 3162 m_buttonEdit.set_sensitive(bValidSelection);
559 schoenebeck 3157 m_applyButton.set_sensitive(isModified());
560 schoenebeck 3162 m_textViewComment.set_sensitive(bValidSelection);
561 schoenebeck 3157 updateStatusBar();
562     }
563    
564     void MacrosSetup::updateStatusBar() {
565     // update status text
566     std::string txt;
567     m_statusLabel.set_markup(txt);
568     }
569    
570     sigc::signal<void, const std::vector<Serialization::Archive>& >& MacrosSetup::signal_macros_changed()
571     {
572     return m_macros_changed;
573     }
574    
575     bool MacrosSetup::onWindowDelete(GdkEventAny* e) {
576     //printf("onWindowDelete\n");
577    
578     if (!isModified()) return false; // propagate event further (which will close this window)
579    
580     //gchar* msg = g_strdup_printf(_("Apply changes to macro \"%s\" before closing?"),
581     // m_macroOriginal->Name.c_str());
582 schoenebeck 3160 gchar* msg = g_strdup_printf(_("Apply changes to macro list before closing?"));
583 schoenebeck 3157 Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
584     g_free(msg);
585     dialog.set_secondary_text(_("If you close without applying, your changes will be lost."));
586     dialog.add_button(_("Close _Without Applying"), Gtk::RESPONSE_NO);
587     dialog.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
588     dialog.add_button(_("_Apply"), Gtk::RESPONSE_YES);
589     dialog.set_default_response(Gtk::RESPONSE_YES);
590     int response = dialog.run();
591     dialog.hide();
592    
593     // user decided to close this window without saving
594     if (response == Gtk::RESPONSE_NO)
595     return false; // propagate event further (which will close this window)
596    
597     // user cancelled dialog, thus don't close this window
598     if (response == Gtk::RESPONSE_CANCEL) {
599     show();
600     return true; // drop event (prevents closing this window)
601     }
602    
603     // user wants to apply the changes, afterwards close window
604     if (response == Gtk::RESPONSE_YES) {
605     onButtonApply();
606     return false; // propagate event further (which will close this window)
607     }
608    
609     // should never ever make it to this point actually
610     return false;
611     }
612    
613     bool MacrosSetup::isModified() const {
614 schoenebeck 3160 if (m_modified) return true;
615 schoenebeck 3157 bool bModified = false;
616     for (int i = 0; i < m_macros.size(); ++i) {
617     if (m_macros[i].isModified()) {
618     bModified = true;
619     break;
620     }
621     }
622     return bModified;
623     }
624    
625     void MacrosSetup::onButtonCancel() {
626     bool dropEvent = onWindowDelete(NULL);
627     if (dropEvent) return;
628     hide();
629     }
630    
631     void MacrosSetup::onButtonApply() {
632     std::string errorText;
633     try {
634     for (int i = 0; i < m_macros.size(); ++i) {
635     if (!m_macros[i].isModified()) continue;
636     // enforce re-encoding the abstract object model and resetting the
637     // 'modified' state
638     m_macros[i].rawData();
639     }
640 schoenebeck 3160 m_modified = false;
641 schoenebeck 3157 } catch (Serialization::Exception e) {
642     errorText = e.Message;
643     } catch (...) {
644     errorText = _("Unknown exception while applying macro changes");
645     }
646     if (!errorText.empty()) {
647     Glib::ustring txt = _("Couldn't apply macro changes:\n") + errorText;
648     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
649     msg.run();
650     } else {
651     // update MainWindow with edited list of macros
652     m_macros_changed.emit(m_macros);
653     }
654     updateStatus();
655     }
656    
657     void MacrosSetup::onWindowHide() {
658     delete this; // this is the end, my friend
659     }

  ViewVC Help
Powered by ViewVC