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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3157 by schoenebeck, Mon May 8 17:30:10 2017 UTC revision 3184 by schoenebeck, Wed May 17 12:28:39 2017 UTC
# Line 9  Line 9 
9  #include "global.h"  #include "global.h"
10  #include <assert.h>  #include <assert.h>
11  #include <set>  #include <set>
12    #include <math.h>
13    #include <gtkmm/stock.h>
14    #include "MacroEditor.h"
15    
16  MacrosSetup::MacrosSetup() :  MacrosSetup::MacrosSetup() :
17        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        m_buttonUp(Gtk::Stock::GO_UP),
22        m_buttonDown(Gtk::Stock::GO_DOWN),
23        m_buttonEdit(Gtk::Stock::EDIT),
24        m_buttonDuplicate(_("Duplicate")),
25      m_statusLabel("",  Gtk::ALIGN_START),      m_statusLabel("",  Gtk::ALIGN_START),
26      m_deleteButton(Glib::ustring(_("Delete")) + " " + UNICODE_PRIMARY_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),      m_labelComment(_("Comment"), Gtk::ALIGN_START),
27      m_inverseDeleteButton(Glib::ustring(_("Inverse Delete")) + " " + UNICODE_ALT_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),      m_deleteButton("  " + Glib::ustring(_("Delete")) + "  " + UNICODE_PRIMARY_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
28      m_applyButton(_("_Apply"), true),      m_inverseDeleteButton("  " + Glib::ustring(_("Inverse Delete")) + "  " + UNICODE_ALT_KEY_SYMBOL + UNICODE_ERASE_KEY_SYMBOL),
29      m_cancelButton(_("_Cancel"), true),      m_applyButton(Gtk::Stock::APPLY),
30      m_altKeyDown(false)      m_cancelButton(Gtk::Stock::CANCEL),
31        m_altKeyDown(false),
32        m_primaryKeyDown(false)
33  {  {
34      add(m_vbox);      add(m_vbox);
35    
36      set_title(_("Setup Macros"));      set_title(_("Setup Macros"));
37    
38      set_default_size(800, 600);      set_default_size(680, 500);
39    
40        m_labelIntro.set_padding(10, 10);
41    #if GTKMM_MAJOR_VERSION >= 3
42        m_labelIntro.set_line_wrap();
43    #endif
44        m_labelIntro.set_text(
45            _("A macro is a list of parameters and corresponding values which "
46              "should be applied to the instrument editor when the macro is "
47              "triggered by the user. A macro is triggered either by selecting "
48              "the macro from the \"Macro\" menu, or by hitting the macro's "
49              "respective keyboard accelerator (F1 to F12), or by applying a "
50              "previously copied macro from the clipboard.")
51        );
52        m_vbox.pack_start(m_labelIntro, Gtk::PACK_SHRINK);
53    
54        m_addFromClipboardButton.set_image(
55            *new Gtk::Image(Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)
56        );
57        m_addFromSelectionButton.set_image(
58            *new Gtk::Image(Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)
59        );
60        m_buttonDuplicate.set_image(
61            *new Gtk::Image(Gtk::Stock::COPY, Gtk::ICON_SIZE_BUTTON)
62        );
63        m_deleteButton.set_image(
64            *new Gtk::Image(Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)
65        );
66        m_inverseDeleteButton.set_image(
67            *new Gtk::Image(Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)
68        );
69        m_addFromClipboardButton.set_tooltip_text(_("Create a new macro from the content currently available on the clipboard."));
70        m_addFromSelectionButton.set_tooltip_text(_("Create a new macro from the currently selected dimension region's parameters currently shown on the main window."));
71        m_buttonDuplicate.set_tooltip_text(_("Duplicate the selected macro(s). The new macro(s) will be appended to the end of the list."));
72        m_buttonUp.set_tooltip_text(
73            _("Move the selected macro up in the list, which changes its order of "
74              "appearance in the main window's \"Macro\" menu and changes to which "
75              "keyboard accelerator key (F1 to F12) the macro is assigned to."));
76        m_buttonDown.set_tooltip_text(
77            _("Move the selected macro down in the list, which changes its order of "
78              "appearance in the main window's \"Macro\" menu and changes to which "
79              "keyboard accelerator key (F1 to F12) the macro is assigned to."));
80        m_buttonEdit.set_tooltip_text(_("Open the Macro Editor for the selected macro."));
81        m_deleteButton.set_tooltip_text(_("Delete the selected macros."));
82        m_inverseDeleteButton.set_tooltip_text(_("Delete all macros except the selected ones."));
83        m_addHBox.pack_start(m_addFromClipboardButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
84        m_addHBox.pack_start(m_addFromSelectionButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
85        m_vbox.pack_start(m_addHBox, Gtk::PACK_SHRINK);
86    
87        m_vbox.pack_start(m_mainHBox);
88        m_vbox.set_spacing(5);
89    
90      // create Macro list treeview (including its data model)      // create Macro list treeview (including its data model)
91      m_treeStoreMacros = MacroListTreeStore::create(m_treeModelMacros);      m_treeStoreMacros = MacroListTreeStore::create(m_treeModelMacros);
# Line 30  MacrosSetup::MacrosSetup() : Line 93  MacrosSetup::MacrosSetup() :
93      m_treeViewMacros.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);      m_treeViewMacros.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
94      //m_treeViewMacro.set_tooltip_text(_(""));      //m_treeViewMacro.set_tooltip_text(_(""));
95      m_treeViewMacros.append_column(_("Key"), m_treeModelMacros.m_col_key);      m_treeViewMacros.append_column(_("Key"), m_treeModelMacros.m_col_key);
96      m_treeViewMacros.append_column_editable(_("Name"), m_treeModelMacros.m_col_name);      m_treeViewMacros.append_column_editable(_("Macro Name"), m_treeModelMacros.m_col_name);
97      m_treeViewMacros.append_column(_("Created"), m_treeModelMacros.m_col_created);      m_treeViewMacros.append_column(_("Created"), m_treeModelMacros.m_col_created);
98      m_treeViewMacros.append_column(_("Modified"), m_treeModelMacros.m_col_modified);      m_treeViewMacros.append_column(_("Modified"), m_treeModelMacros.m_col_modified);
99      m_treeViewMacros.set_tooltip_column(m_treeModelMacros.m_col_comment.index());      m_treeViewMacros.set_tooltip_column(m_treeModelMacros.m_col_comment.index());
# Line 63  MacrosSetup::MacrosSetup() : Line 126  MacrosSetup::MacrosSetup() :
126      m_treeViewMacros.get_selection()->signal_changed().connect(      m_treeViewMacros.get_selection()->signal_changed().connect(
127          sigc::mem_fun(*this, &MacrosSetup::onTreeViewSelectionChanged)          sigc::mem_fun(*this, &MacrosSetup::onTreeViewSelectionChanged)
128      );      );
129      /*m_treeViewMacros.signal_key_release_event().connect_notify(      m_treeViewMacros.signal_key_release_event().connect_notify(
130          sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewKeyRelease)          sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewKeyRelease)
131      );*/      );
132      m_treeStoreMacros->signal_row_changed().connect(      m_treeStoreMacros->signal_row_changed().connect(
133          sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewRowValueChanged)          sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewRowValueChanged)
134      );      );
135      m_ignoreTreeViewValueChange = false;      m_ignoreTreeViewValueChange = false;
136        m_ignoreCommentTextViewChange = false;
137    
138      m_scrolledWindow.add(m_treeViewMacros);      m_scrolledWindow.add(m_treeViewMacros);
139      m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);      m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
140      m_vbox.pack_start(m_scrolledWindow);      m_mainHBox.pack_start(m_scrolledWindow);
141    
142        m_rvbox.set_spacing(5);
143    
144        m_mainHBox.pack_start(m_rvbox, Gtk::PACK_SHRINK);
145        m_mainHBox.set_spacing(5),
146        m_rvbox.set_spacing(5);
147        m_rvbox.pack_start(m_buttonDuplicate, Gtk::PACK_SHRINK);
148        m_rvbox.pack_start(m_detailsButtonBox, Gtk::PACK_SHRINK);
149    
150        //m_textViewComment.set_left_margin(3);
151        //m_textViewComment.set_right_margin(3);
152        m_textViewComment.set_indent(2);
153        m_textViewComment.set_tooltip_text(
154            _("Write arbitrary comments for the selected macro which help you to "
155              "remember the purpose of your macro. The comment will be shown as "
156              "tooltip in the main window's \"Macro\" menu for example.")
157        );
158        m_scrolledWindowComment.add(m_textViewComment);
159        m_scrolledWindowComment.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
160        m_labelComment.set_markup(
161            "<b>" + m_labelComment.get_text() + "</b>"
162        );
163        m_rvbox.pack_start(m_labelComment, Gtk::PACK_SHRINK);
164        m_rvbox.pack_start(m_scrolledWindowComment);
165    
166        m_detailsButtonBox.pack_start(m_buttonUp);
167        m_detailsButtonBox.pack_start(m_buttonDown);
168        m_detailsButtonBox.pack_start(m_buttonEdit);
169    
170      m_buttonBoxL.set_layout(Gtk::BUTTONBOX_START);      m_buttonBoxL.set_layout(Gtk::BUTTONBOX_START);
171      m_buttonBoxL.pack_start(m_deleteButton);      m_buttonBoxL.pack_start(m_deleteButton);
172      m_buttonBoxL.pack_start(m_inverseDeleteButton);      m_buttonBoxL.pack_start(m_inverseDeleteButton);
173      m_deleteButton.set_sensitive(false);      m_deleteButton.set_sensitive(false);
174      m_inverseDeleteButton.set_sensitive(false);      m_inverseDeleteButton.set_sensitive(false);
175        m_buttonDuplicate.set_sensitive(false);
176        m_buttonUp.set_sensitive(false);
177        m_buttonDown.set_sensitive(false);
178    
179      m_buttonBox.set_layout(Gtk::BUTTONBOX_END);      m_buttonBox.set_layout(Gtk::BUTTONBOX_END);
180      m_buttonBox.pack_start(m_applyButton);      m_buttonBox.pack_start(m_applyButton);
# Line 104  MacrosSetup::MacrosSetup() : Line 199  MacrosSetup::MacrosSetup() :
199    
200      m_vbox.pack_start(m_footerHBox, Gtk::PACK_SHRINK);      m_vbox.pack_start(m_footerHBox, Gtk::PACK_SHRINK);
201    
202        m_addFromClipboardButton.signal_clicked().connect(
203            sigc::mem_fun(*this, &MacrosSetup::onButtonAddFromClipboard)
204        );
205    
206        m_addFromSelectionButton.signal_clicked().connect(
207            sigc::mem_fun(*this, &MacrosSetup::onButtonAddFromSelection)
208        );
209    
210        m_buttonUp.signal_clicked().connect(
211            sigc::mem_fun(*this, &MacrosSetup::onButtonUp)
212        );
213    
214        m_buttonDown.signal_clicked().connect(
215            sigc::mem_fun(*this, &MacrosSetup::onButtonDown)
216        );
217    
218        m_buttonEdit.signal_clicked().connect(
219            sigc::mem_fun(*this, &MacrosSetup::onButtonEdit)
220        );
221    
222        m_buttonDuplicate.signal_clicked().connect(
223            sigc::mem_fun(*this, &MacrosSetup::onButtonDuplicate)
224        );
225    
226        m_textViewComment.get_buffer()->signal_changed().connect(
227            sigc::mem_fun(*this, &MacrosSetup::onCommentTextViewChanged)
228        );
229    
230      m_applyButton.signal_clicked().connect(      m_applyButton.signal_clicked().connect(
231          sigc::mem_fun(*this, &MacrosSetup::onButtonApply)          sigc::mem_fun(*this, &MacrosSetup::onButtonApply)
232      );      );
# Line 143  MacrosSetup::~MacrosSetup() { Line 266  MacrosSetup::~MacrosSetup() {
266      printf("MacrosSetup destruct\n");      printf("MacrosSetup destruct\n");
267  }  }
268    
269  void MacrosSetup::setMacros(const std::vector<Serialization::Archive>& macros) {  void MacrosSetup::setMacros(const std::vector<Serialization::Archive>& macros,
270                                Serialization::Archive* pClipboardContent,
271                                gig::DimensionRegion* pSelectedDimRgn)
272    {
273      // copy for non-destructive editing      // copy for non-destructive editing
274      m_macros = macros;      m_macros = macros;
275    
276        m_clipboardContent = pClipboardContent;
277        m_selectedDimRgn = pSelectedDimRgn;
278    
279        reloadTreeView();
280    }
281    
282    void MacrosSetup::onButtonAddFromClipboard() {
283        printf("+fromClipboard\n");
284        if (!m_clipboardContent) return;
285        if (!m_clipboardContent->rootObject()) return;
286        m_macros.push_back(*m_clipboardContent);
287        m_modified = true;
288      reloadTreeView();      reloadTreeView();
289  }  }
290    
291    void MacrosSetup::onButtonAddFromSelection() {
292        printf("+fromSelection\n");
293        if (!m_selectedDimRgn) return;
294        std::string errorText;
295        try {
296            Serialization::Archive archive;
297            archive.serialize(m_selectedDimRgn);
298            //archive.setName("Unnamed Macro");
299            m_macros.push_back(archive);
300            m_modified = true;
301            reloadTreeView();
302        } catch (Serialization::Exception e) {
303            errorText = e.Message;
304        } catch (...) {
305            errorText = _("Unknown exception while creating macro");
306        }
307        if (!errorText.empty()) {
308            Glib::ustring txt = _("Couldn't create macro:\n") + errorText;
309            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
310            msg.run();
311        }
312    }
313    
314    void MacrosSetup::moveByDir(int d) {
315        if (d < -1 || d > 1) return;
316        int index = getSelectedMacroIndex();
317        if (index < 0) return;
318        if (d == -1 && index == 0) return;
319        if (d == +1 && index >= m_macros.size() - 1) return;
320    
321        // swap macros
322        std::swap(m_macros[index + d], m_macros[index]);
323    
324        // swap tree view rows
325        Gtk::TreePath p1(ToString(index + d));
326        Gtk::TreePath p2(ToString(index));
327        Gtk::TreeModel::iterator it1 = m_treeStoreMacros->get_iter(p1);
328        Gtk::TreeModel::iterator it2 = m_treeStoreMacros->get_iter(p2);
329        m_treeStoreMacros->iter_swap(it1, it2);
330        int idx1 = (*it1)[m_treeModelMacros.m_col_index];
331        int idx2 = (*it2)[m_treeModelMacros.m_col_index];
332        (*it1)[m_treeModelMacros.m_col_index] = idx2;
333        (*it2)[m_treeModelMacros.m_col_index] = idx1;
334        Glib::ustring s1 = (*it1)[m_treeModelMacros.m_col_key];
335        Glib::ustring s2 = (*it2)[m_treeModelMacros.m_col_key];
336        (*it1)[m_treeModelMacros.m_col_key] = s2;
337        (*it2)[m_treeModelMacros.m_col_key] = s1;
338    
339        m_modified = true;
340    }
341    
342    void MacrosSetup::onButtonUp() {
343        moveByDir(-1);
344    }
345    
346    void MacrosSetup::onButtonDown() {
347        moveByDir(+1);
348    }
349    
350    void MacrosSetup::onButtonDuplicate() {
351        Glib::RefPtr<Gtk::TreeSelection> sel = m_treeViewMacros.get_selection();
352        std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
353        duplicateRows(rows);
354    }
355    
356    void MacrosSetup::onButtonEdit() {
357        Serialization::Archive* macro = getSelectedMacro();
358        if (!macro) return;
359    
360        m_modifiedBeforeMacroEditor = isModified();
361    
362        MacroEditor* editor = new MacroEditor();
363        editor->setMacro(macro, false);
364        editor->signal_changes_applied().connect(
365            sigc::mem_fun(*this, &MacrosSetup::onMacroEditorAppliedChanges)
366        );
367        editor->show();
368    }
369    
370    void MacrosSetup::onMacroEditorAppliedChanges() {
371        // so that the user does not need to click on a Apply buttons twice
372        if (!m_modifiedBeforeMacroEditor)
373            onButtonApply();
374        updateStatus();
375    }
376    
377    void MacrosSetup::onCommentTextViewChanged() {
378        if (m_ignoreCommentTextViewChange) return;
379        //printf("textChanged\n");
380        Serialization::Archive* macro = getSelectedMacro();
381        if (!macro) return;
382        macro->setComment(
383            m_textViewComment.get_buffer()->get_text()
384        );
385        updateStatus();
386    }
387    
388    int MacrosSetup::getSelectedMacroIndex() const {
389        std::vector<Gtk::TreeModel::Path> v = m_treeViewMacros.get_selection()->get_selected_rows();
390        if (v.empty()) return -1;
391        Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(v[0]);
392        if (!it) return -1;
393        const Gtk::TreeModel::Row& row = *it;
394        int index = row[m_treeModelMacros.m_col_index];
395        if (index < 0 || index >= m_macros.size()) return -1;
396        return index;
397    }
398    
399    Serialization::Archive* MacrosSetup::getSelectedMacro() {
400        int index = getSelectedMacroIndex();
401        if (index < 0) return NULL;
402        return &m_macros[index];
403    }
404    
405  static Glib::ustring indexToAccKey(uint index) {  static Glib::ustring indexToAccKey(uint index) {
406      if (index >= 12) return "";      if (index >= 12) return "";
407      return "F" + ToString(index+1);      return "F" + ToString(index+1);
408  }  }
409    
410    static int daysAgo(const tm& t) {
411        time_t now;
412        time(&now);
413        tm* pNow = localtime(&now);
414        if (!pNow) return 0;
415        if (pNow->tm_year == t.tm_year &&
416            pNow->tm_mon  == t.tm_mon &&
417            pNow->tm_mday == t.tm_mday) return 0;
418        time_t past = mktime((tm*)&t);
419        return ceil(difftime(now, past) / 60.0 / 60.0 / 24.0);
420    }
421    
422  static Glib::ustring humanShortStr(const tm& t) {  static Glib::ustring humanShortStr(const tm& t) {
423        int iDaysAgo = daysAgo(t);
424      char buf[70];      char buf[70];
425      int daysAgo;      if (iDaysAgo == 0) {
     if (daysAgo = 0) {  
426          // C-Time specification for a time somewhere today (see 'man strftime()').          // C-Time specification for a time somewhere today (see 'man strftime()').
427          if (strftime(buf, sizeof buf, _("%R"), &t))          if (strftime(buf, sizeof buf, _("%R"), &t))
428              return buf;              return buf;
429      } else if (daysAgo = 1) {      } else if (iDaysAgo == 1) {
430          // C-Time specification for a time somewhere yesterday (see 'man strftime()').          // C-Time specification for a time somewhere yesterday (see 'man strftime()').
431          if (strftime(buf, sizeof buf, _("Yesterday %R"), &t))          if (strftime(buf, sizeof buf, _("Yesterday %R"), &t))
432              return buf;              return buf;
433      } else if (daysAgo = 2) {      } else if (iDaysAgo == 2) {
434          // C-Time specification for a time somewhere 2 days ago (see 'man strftime()').          // C-Time specification for a time somewhere 2 days ago (see 'man strftime()').
435          if (strftime(buf, sizeof buf, _("2 days ago %R"), &t))          if (strftime(buf, sizeof buf, _("2 days ago %R"), &t))
436              return buf;              return buf;
# Line 189  void MacrosSetup::reloadTreeView() { Line 453  void MacrosSetup::reloadTreeView() {
453          Gtk::TreeModel::iterator iter = m_treeStoreMacros->append();          Gtk::TreeModel::iterator iter = m_treeStoreMacros->append();
454          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
455          row[m_treeModelMacros.m_col_key] = indexToAccKey(iMacro);          row[m_treeModelMacros.m_col_key] = indexToAccKey(iMacro);
456          row[m_treeModelMacros.m_col_name] = gig_to_utf8(macro.name());          row[m_treeModelMacros.m_col_name] = macro.name().empty() ? _("Unnamed Macro") : gig_to_utf8(macro.name());
457          row[m_treeModelMacros.m_col_comment] = gig_to_utf8(macro.comment());          row[m_treeModelMacros.m_col_comment] = macro.comment().empty() ? _("No comment assigned to this macro yet.") : gig_to_utf8(macro.comment());
458          row[m_treeModelMacros.m_col_created] = humanShortStr(macro.dateTimeCreated());          row[m_treeModelMacros.m_col_created] = humanShortStr(macro.dateTimeCreated());
459          row[m_treeModelMacros.m_col_modified] = humanShortStr(macro.dateTimeModified());          row[m_treeModelMacros.m_col_modified] = humanShortStr(macro.dateTimeModified());
460          row[m_treeModelMacros.m_col_index] = iMacro;          row[m_treeModelMacros.m_col_index] = iMacro;
# Line 208  void MacrosSetup::onTreeViewSelectionCha Line 472  void MacrosSetup::onTreeViewSelectionCha
472      const bool bValidSelection = !v.empty();      const bool bValidSelection = !v.empty();
473      m_deleteButton.set_sensitive(bValidSelection);      m_deleteButton.set_sensitive(bValidSelection);
474      m_inverseDeleteButton.set_sensitive(bValidSelection);      m_inverseDeleteButton.set_sensitive(bValidSelection);
475  }      m_buttonEdit.set_sensitive(bValidSelection);
476        m_buttonDuplicate.set_sensitive(bValidSelection);
477        m_buttonUp.set_sensitive(bValidSelection);
478        m_buttonDown.set_sensitive(bValidSelection);
479    
480        // update comment text view
481        std::string sComment;
482        Serialization::Archive* macro = getSelectedMacro();
483        if (macro)
484            sComment = macro->comment();
485        m_ignoreCommentTextViewChange = true;
486        m_textViewComment.get_buffer()->set_text(sComment);
487        m_ignoreCommentTextViewChange = false;
488        m_textViewComment.set_sensitive(bValidSelection);
489    }
490    
491    // Cmd key on Mac, Ctrl key on all other OSs
492    static const guint primaryKeyL =
493        #if defined(__APPLE__)
494        GDK_KEY_Meta_L;
495        #else
496        GDK_KEY_Control_L;
497        #endif
498    
499    static const guint primaryKeyR =
500        #if defined(__APPLE__)
501        GDK_KEY_Meta_R;
502        #else
503        GDK_KEY_Control_R;
504        #endif
505    
506  bool MacrosSetup::onKeyPressed(GdkEventKey* key) {  bool MacrosSetup::onKeyPressed(GdkEventKey* key) {
507      //printf("key down 0x%x\n", key->keyval);      //printf("key down 0x%x\n", key->keyval);
508      if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)      if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
509          m_altKeyDown = true;          m_altKeyDown = true;
510        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
511            m_primaryKeyDown = true;
512      return false;      return false;
513  }  }
514    
# Line 221  bool MacrosSetup::onKeyReleased(GdkEvent Line 516  bool MacrosSetup::onKeyReleased(GdkEvent
516      //printf("key up 0x%x\n", key->keyval);      //printf("key up 0x%x\n", key->keyval);
517      if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)      if (key->keyval == GDK_KEY_Alt_L || key->keyval == GDK_KEY_Alt_R)
518          m_altKeyDown = false;          m_altKeyDown = false;
519        if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
520            m_primaryKeyDown = false;
521        if (m_primaryKeyDown && key->keyval == GDK_KEY_b)
522            onButtonAddFromClipboard();
523        if (m_primaryKeyDown && key->keyval == GDK_KEY_s)
524            onButtonAddFromSelection();
525      return false;      return false;
526  }  }
527    
# Line 228  void MacrosSetup::onMacroTreeViewKeyRele Line 529  void MacrosSetup::onMacroTreeViewKeyRele
529      if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete) {      if (key->keyval == GDK_KEY_BackSpace || key->keyval == GDK_KEY_Delete) {
530          if (m_altKeyDown)          if (m_altKeyDown)
531              inverseDeleteSelectedRows();              inverseDeleteSelectedRows();
532          else          else if (m_primaryKeyDown)
533              deleteSelectedRows();              deleteSelectedRows();
534      }      }
535  }  }
# Line 243  void MacrosSetup::onMacroTreeViewRowValu Line 544  void MacrosSetup::onMacroTreeViewRowValu
544      int index = row[m_treeModelMacros.m_col_index];      int index = row[m_treeModelMacros.m_col_index];
545      m_macros[index].setName(name);      m_macros[index].setName(name);
546      //reloadTreeView();      //reloadTreeView();
547        m_modified = true;
548        updateStatus();
549  }  }
550    
551  void MacrosSetup::deleteSelectedRows() {  void MacrosSetup::deleteSelectedRows() {
# Line 251  void MacrosSetup::deleteSelectedRows() { Line 554  void MacrosSetup::deleteSelectedRows() {
554      deleteRows(rows);      deleteRows(rows);
555  }  }
556    
557    void MacrosSetup::duplicateRows(const std::vector<Gtk::TreeModel::Path>& rows) {
558        if (!rows.empty()) m_modified = true;
559        bool bError = false;
560        for (int r = 0; r < rows.size(); ++r) {
561            Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(rows[r]);
562            if (!it) continue;
563            Gtk::TreeModel::Row row = *it;
564            int index = row[m_treeModelMacros.m_col_index];
565            if (index < 0 || index >= m_macros.size()) continue;
566    
567            Serialization::Archive clone = m_macros[index];
568            if (!endsWith(clone.name(), "COPY", true)) {
569                clone.setName(
570                    (clone.name().empty()) ? "Unnamed COPY" : (clone.name() + " COPY")
571                );
572            }
573            try {
574                // enforce re-encoding the abstract object model and resetting the
575                // 'modified' state
576                clone.rawData();
577            } catch (Serialization::Exception e) {
578                bError = true;
579                e.PrintMessage();
580                continue;
581            } catch (...) {
582                bError = true;
583                std::cerr << "Unknown exception while cloning macro." << std::endl;
584                continue;
585            }
586            // finally add new cloned macro
587            m_macros.push_back(clone);
588        }
589        reloadTreeView();
590        if (bError) {
591            Glib::ustring txt = _("At least one of the macros could not be cloned due to an error (check console output).");
592            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
593            msg.run();
594        }
595    }
596    
597  void MacrosSetup::deleteRows(const std::vector<Gtk::TreeModel::Path>& rows) {  void MacrosSetup::deleteRows(const std::vector<Gtk::TreeModel::Path>& rows) {
598        if (!rows.empty()) m_modified = true;
599      std::set<int> macros;      std::set<int> macros;
600      for (int r = rows.size() - 1; r >= 0; --r) {      for (int r = rows.size() - 1; r >= 0; --r) {
601          Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(rows[r]);          Gtk::TreeModel::iterator it = m_treeStoreMacros->get_iter(rows[r]);
# Line 298  void MacrosSetup::inverseDeleteSelectedR Line 642  void MacrosSetup::inverseDeleteSelectedR
642  }  }
643    
644  void MacrosSetup::updateStatus() {  void MacrosSetup::updateStatus() {
645        bool bValidSelection = !m_treeViewMacros.get_selection()->get_selected_rows().empty();
646        m_addFromClipboardButton.set_sensitive(
647            m_clipboardContent && m_clipboardContent->rootObject()
648        );
649        m_addFromSelectionButton.set_sensitive(m_selectedDimRgn);
650        m_buttonEdit.set_sensitive(bValidSelection);
651        m_buttonDuplicate.set_sensitive(bValidSelection);
652        m_buttonUp.set_sensitive(bValidSelection);
653        m_buttonDown.set_sensitive(bValidSelection);
654      m_applyButton.set_sensitive(isModified());      m_applyButton.set_sensitive(isModified());
655        m_textViewComment.set_sensitive(bValidSelection);
656      updateStatusBar();      updateStatusBar();
657  }  }
658    
# Line 320  bool MacrosSetup::onWindowDelete(GdkEven Line 674  bool MacrosSetup::onWindowDelete(GdkEven
674    
675      //gchar* msg = g_strdup_printf(_("Apply changes to macro \"%s\" before closing?"),      //gchar* msg = g_strdup_printf(_("Apply changes to macro \"%s\" before closing?"),
676      //                             m_macroOriginal->Name.c_str());      //                             m_macroOriginal->Name.c_str());
677      gchar* msg = g_strdup_printf(_("Apply changes to macro before closing?"));      gchar* msg = g_strdup_printf(_("Apply changes to macro list before closing?"));
678      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
679      g_free(msg);      g_free(msg);
680      dialog.set_secondary_text(_("If you close without applying, your changes will be lost."));      dialog.set_secondary_text(_("If you close without applying, your changes will be lost."));
# Line 352  bool MacrosSetup::onWindowDelete(GdkEven Line 706  bool MacrosSetup::onWindowDelete(GdkEven
706  }  }
707    
708  bool MacrosSetup::isModified() const {  bool MacrosSetup::isModified() const {
709        if (m_modified) return true;
710      bool bModified = false;      bool bModified = false;
711      for (int i = 0; i < m_macros.size(); ++i) {      for (int i = 0; i < m_macros.size(); ++i) {
712          if (m_macros[i].isModified()) {          if (m_macros[i].isModified()) {
# Line 377  void MacrosSetup::onButtonApply() { Line 732  void MacrosSetup::onButtonApply() {
732              // 'modified' state              // 'modified' state
733              m_macros[i].rawData();              m_macros[i].rawData();
734          }          }
735            m_modified = false;
736      } catch (Serialization::Exception e) {      } catch (Serialization::Exception e) {
737          errorText = e.Message;          errorText = e.Message;
738      } catch (...) {      } catch (...) {

Legend:
Removed from v.3157  
changed lines
  Added in v.3184

  ViewVC Help
Powered by ViewVC