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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3162 - (show 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 /*
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 #include <math.h>
13 #include <gtkmm/stock.h>
14 #include "MacroEditor.h"
15
16 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_statusLabel("", Gtk::ALIGN_START),
25 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 m_altKeyDown(false),
31 m_primaryKeyDown(false)
32 {
33 add(m_vbox);
34
35 set_title(_("Setup Macros"));
36
37 set_default_size(680, 500);
38
39 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 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 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 m_addHBox.pack_start(m_addFromClipboardButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
54 m_addHBox.pack_start(m_addFromSelectionButton, Gtk::PACK_EXPAND_WIDGET/*, 15*/);
55 m_vbox.pack_start(m_addHBox, Gtk::PACK_SHRINK);
56
57 m_vbox.pack_start(m_mainHBox);
58 m_vbox.set_spacing(5);
59
60 // 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 m_treeViewMacros.append_column_editable(_("Macro Name"), m_treeModelMacros.m_col_name);
67 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 m_treeViewMacros.signal_key_release_event().connect_notify(
100 sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewKeyRelease)
101 );
102 m_treeStoreMacros->signal_row_changed().connect(
103 sigc::mem_fun(*this, &MacrosSetup::onMacroTreeViewRowValueChanged)
104 );
105 m_ignoreTreeViewValueChange = false;
106 m_ignoreCommentTextViewChange = false;
107
108 m_scrolledWindow.add(m_treeViewMacros);
109 m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
110 m_mainHBox.pack_start(m_scrolledWindow);
111
112 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 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 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 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 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 void MacrosSetup::setMacros(const std::vector<Serialization::Archive>& macros,
227 Serialization::Archive* pClipboardContent,
228 gig::DimensionRegion* pSelectedDimRgn)
229 {
230 // copy for non-destructive editing
231 m_macros = macros;
232
233 m_clipboardContent = pClipboardContent;
234 m_selectedDimRgn = pSelectedDimRgn;
235
236 reloadTreeView();
237 }
238
239 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 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 static Glib::ustring indexToAccKey(uint index) {
357 if (index >= 12) return "";
358 return "F" + ToString(index+1);
359 }
360
361 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 return ceil(difftime(now, past) / 60.0 / 60.0 / 24.0);
371 }
372
373 static Glib::ustring humanShortStr(const tm& t) {
374 int iDaysAgo = daysAgo(t);
375 char buf[70];
376 if (iDaysAgo == 0) {
377 // C-Time specification for a time somewhere today (see 'man strftime()').
378 if (strftime(buf, sizeof buf, _("%R"), &t))
379 return buf;
380 } else if (iDaysAgo == 1) {
381 // C-Time specification for a time somewhere yesterday (see 'man strftime()').
382 if (strftime(buf, sizeof buf, _("Yesterday %R"), &t))
383 return buf;
384 } else if (iDaysAgo == 2) {
385 // 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 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 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 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 }
438
439 // 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 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 if (key->keyval == primaryKeyL || key->keyval == primaryKeyR)
459 m_primaryKeyDown = true;
460 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 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 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 else if (m_primaryKeyDown)
481 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 m_modified = true;
496 updateStatus();
497 }
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 m_modified = !rows.empty();
507 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 bool bValidSelection = !m_treeViewMacros.get_selection()->get_selected_rows().empty();
554 m_addFromClipboardButton.set_sensitive(
555 m_clipboardContent && m_clipboardContent->rootObject()
556 );
557 m_addFromSelectionButton.set_sensitive(m_selectedDimRgn);
558 m_buttonEdit.set_sensitive(bValidSelection);
559 m_applyButton.set_sensitive(isModified());
560 m_textViewComment.set_sensitive(bValidSelection);
561 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 gchar* msg = g_strdup_printf(_("Apply changes to macro list before closing?"));
583 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 if (m_modified) return true;
615 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 m_modified = false;
641 } 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