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

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

  ViewVC Help
Powered by ViewVC