Guitarix
gx_preset_window.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * ---------------------------------------------------------------------------
19  *
20  *
21  * ----------------------------------------------------------------------------
22  */
23 
24 #include <guitarix.h>
25 
26 /****************************************************************
27  ** class PresetWindow
28  */
29 
30 PresetStore::PresetStore(): Gtk::ListStore(), col() {
31  set_column_types(col);
32 }
33 
34 bool PresetStore::row_draggable_vfunc(const TreeModel::Path& path) const {
35  Gtk::TreeModel::const_iterator i = const_cast<PresetStore*>(this)->get_iter(path); // Bug in Gtkmm: no get_iter() const
36  Glib::ustring s(i->get_value(col.name));
37  if (s.empty()) {
38  return false;
39  } else {
40  return true;
41  }
42 }
43 
44 
45 PresetWindow::PresetWindow(Glib::RefPtr<gx_gui::GxBuilder> bld, gx_engine::GxMachineBase& machine_,
46  const gx_system::CmdlineOptions& options_, GxActions& actions_, GtkSizeGroup *lc)
47  : sigc::trackable(),
48  machine(machine_),
49  actions(actions_),
50  in_edit(false),
51  edit_iter(),
52  pb_edit(),
53  pb_del(),
54  pb_scratch(),
55  pb_versiondiff(),
56  pb_readonly(),
57  pb_factory(),
58  pstore(new PresetStore),
59  target_col(),
60  bank_col(),
61  bank_row_del_conn(),
62  preset_row_del_conn(),
63  vpaned_pos(),
64  vpaned_step(),
65  vpaned_target(),
66  options(options_),
67  in_current_preset(false),
68  on_map_conn()
69  /* widget pointers not initialized */ {
70  load_widget_pointers(bld);
71  actions.new_bank = Gtk::Action::create("NewBank");
72  actions.group->add(actions.new_bank, sigc::mem_fun(*this, &PresetWindow::on_new_bank));
73  gtk_activatable_set_related_action(GTK_ACTIVATABLE(new_preset_bank->gobj()), actions.new_bank->gobj());
74  actions.save_changes = Gtk::Action::create("Save", _("_Save changes"));
75  actions.group->add(actions.save_changes, sigc::mem_fun(*this, &PresetWindow::on_preset_save));
76  gtk_activatable_set_related_action(GTK_ACTIVATABLE(save_preset->gobj()), actions.save_changes->gobj());
77  actions.organize = Gtk::ToggleAction::create("Organize", _("_Organize"));
78  actions.group->add(actions.organize, sigc::mem_fun(*this, &PresetWindow::on_organize));
79  gtk_activatable_set_related_action(GTK_ACTIVATABLE(organize_presets->gobj()), GTK_ACTION(actions.organize->gobj()));
80  //act = Gtk::Action::create("ClosePresetsAction");
81  //actiongroup->add(act, sigc::mem_fun(*this, &PresetWindow::on_presets_close));
82  //gtk_activatable_set_related_action(GTK_ACTIVATABLE(close_preset->gobj()), act->gobj());
83  close_preset->hide(); // disable (maybe remove later)
84 #ifdef HAVE_WEBKIT
85  actions.online_preset_bank = Gtk::Action::create("OnlineBank");
86  actions.group->add(actions.online_preset_bank, sigc::mem_fun(*this, &PresetWindow::on_online_preset));
87  gtk_activatable_set_related_action(GTK_ACTIVATABLE(online_preset->gobj()), actions.online_preset_bank->gobj());
88 #else
89  online_preset->set_sensitive(false);
90 #endif
91  bank_treeview->set_model(Gtk::ListStore::create(bank_col));
92  bank_treeview->set_name("PresetView");
93  bank_treeview->get_selection()->set_select_function(
94  sigc::mem_fun(*this, &PresetWindow::select_func));
95  bank_treeview->set_has_tooltip(true);
96  bank_treeview->signal_query_tooltip().connect(
97  sigc::mem_fun(*this, &PresetWindow::on_bank_query_tooltip));
98  pb_edit = bank_treeview->render_icon(Gtk::Stock::EDIT, Gtk::ICON_SIZE_MENU);
99  pb_del = bank_treeview->render_icon(Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU);
100  pb_scratch = Gdk::Pixbuf::create_from_file(options.get_style_filepath("scratch.png"));
101  pb_versiondiff = Gdk::Pixbuf::create_from_file(options.get_style_filepath("versiondiff.png"));
102  pb_readonly = Gdk::Pixbuf::create_from_file(options.get_style_filepath("readonly.png"));
103  pb_factory = Gdk::Pixbuf::create_from_file(options.get_style_filepath("factory.png"));
104  bank_treeview->set_row_separator_func(sigc::mem_fun(*this, &PresetWindow::is_row_separator));
105  bank_cellrenderer->signal_edited().connect(
106  sigc::bind(sigc::mem_fun(*this, &PresetWindow::on_bank_edited), bank_treeview));
107  bank_cellrenderer->signal_editing_canceled().connect(
108  sigc::bind(sigc::mem_fun(*this, &PresetWindow::on_edit_canceled), bank_treeview->get_column(1)));
109  bank_cellrenderer->signal_editing_started().connect(
110  sigc::bind(sigc::mem_fun(*this, &PresetWindow::on_editing_started), bank_treeview->get_model()));
111  Gtk::TreeViewColumn *col = bank_treeview->get_column(1);
112  col->set_cell_data_func(**col->get_cell_renderers().begin(), sigc::mem_fun(*this, &PresetWindow::highlight_current_bank));
113 
114  std::vector<Gtk::TargetEntry> listTargets;
115  listTargets.push_back(Gtk::TargetEntry("GTK_TREE_MODEL_ROW", Gtk::TARGET_SAME_WIDGET, MODELROW_TARGET));
116  listTargets.push_back(Gtk::TargetEntry("text/uri-list", Gtk::TARGET_OTHER_APP, URILIST_TARGET));
117  bank_treeview->enable_model_drag_source(listTargets, Gdk::BUTTON1_MASK, Gdk::ACTION_COPY);
118  bank_treeview->drag_source_add_text_targets(); // sets info == 0 (TEXT_TARGETS)
119  bank_treeview->signal_drag_motion().connect(sigc::mem_fun(*this, &PresetWindow::on_bank_drag_motion), false);
120  bank_treeview->enable_model_drag_dest(listTargets, Gdk::ACTION_COPY);
121  bank_treeview->signal_drag_data_received().connect(
122  sigc::mem_fun(*this, &PresetWindow::on_bank_drag_data_received));
123  bank_treeview->signal_drag_data_get().connect(
124  sigc::mem_fun(*this, &PresetWindow::on_bank_drag_data_get));
125  bank_treeview->signal_drag_begin().connect(
126  sigc::hide(sigc::mem_fun(machine, &gx_engine::GxMachineBase::bank_drag_begin)));
127  Glib::RefPtr<Gtk::TreeSelection> sel = bank_treeview->get_selection();
128  sel->set_mode(Gtk::SELECTION_BROWSE);
129  sel->signal_changed().connect(sigc::mem_fun(*this, &PresetWindow::on_bank_changed));
130  bank_treeview->signal_button_release_event().connect(sigc::mem_fun(*this, &PresetWindow::on_bank_button_release), true);
131  Glib::RefPtr<Gtk::TreeModel> ls = bank_treeview->get_model();
132  bank_row_del_conn = ls->signal_row_deleted().connect(sigc::mem_fun(*this, &PresetWindow::on_bank_reordered));
133 
134  preset_treeview->set_model(pstore);
135  preset_treeview->set_name("PresetView");
136  preset_treeview->signal_drag_motion().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_drag_motion), false);
137  preset_treeview->signal_drag_data_get().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_drag_data_get));
138  preset_treeview->signal_row_activated().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_row_activated));
139  preset_treeview->signal_button_press_event().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_button_press));
140  preset_treeview->signal_button_release_event().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_button_release), true);
141  preset_row_del_conn = pstore->signal_row_deleted().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_reordered));
142  preset_treeview->get_selection()->set_mode(Gtk::SELECTION_BROWSE);
143  preset_treeview->get_selection()->set_select_function(
144  sigc::mem_fun(*this, &PresetWindow::select_func));
145  preset_treeview->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_changed));
146  preset_treeview->signal_cursor_changed().connect(sigc::mem_fun(*this, &PresetWindow::on_cursor_changed));
147  preset_cellrenderer->signal_edited().connect(sigc::mem_fun(*this, &PresetWindow::on_preset_edited));
148  preset_cellrenderer->signal_editing_canceled().connect(
149  sigc::bind(sigc::mem_fun(*this, &PresetWindow::on_edit_canceled), preset_treeview->get_column(0)));
150  preset_cellrenderer->signal_editing_started().connect(
151  sigc::bind(
152  sigc::mem_fun(*this, &PresetWindow::on_editing_started),
153  Glib::RefPtr<Gtk::TreeModel>::cast_static(pstore)));
154  preset_treeview->get_column(0)->set_cell_data_func(
155  *preset_cellrenderer, sigc::mem_fun(*this, &PresetWindow::text_func));
156  banks_combobox->signal_changed().connect(
157  sigc::mem_fun(*this, &PresetWindow::on_preset_combo_changed));
158  presets_target_treeview->get_selection()->set_mode(Gtk::SELECTION_NONE);
159  std::vector<Gtk::TargetEntry> listTargets3;
160  listTargets3.push_back(
161  Gtk::TargetEntry("application/x-guitarix-preset", Gtk::TARGET_SAME_APP, 0));
162  presets_target_treeview->enable_model_drag_dest(listTargets3, Gdk::ACTION_COPY);
163  presets_target_treeview->signal_drag_motion().connect(
164  sigc::mem_fun(*this, &PresetWindow::on_target_drag_motion), false);
165  presets_target_treeview->signal_drag_data_received().connect_notify(
166  sigc::mem_fun(*this, &PresetWindow::target_drag_data_received));
167  machine.signal_selection_changed().connect(
168  sigc::mem_fun(*this, &PresetWindow::on_selection_changed));
169 
170  left_column = lc;
171  gtk_size_group_add_widget(lc, GTK_WIDGET(close_preset->gobj()));
172  gtk_size_group_add_widget(lc, GTK_WIDGET(save_preset->gobj()));
173  gtk_size_group_add_widget(lc, GTK_WIDGET(new_preset_bank->gobj()));
174  gtk_size_group_add_widget(lc, GTK_WIDGET(organize_presets->gobj()));
175  gtk_size_group_add_widget(lc, GTK_WIDGET(online_preset->gobj()));
176 }
177 
179 }
180 
181 void PresetWindow::on_selection_changed() {
182  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
183  if (it && it->get_value(bank_col.name) == machine.get_current_bank()) {
184  it = preset_treeview->get_selection()->get_selected();
185  if (it && it->get_value(pstore->col.name) == machine.get_current_name()) {
186  Glib::RefPtr<Gdk::Window> w = bank_treeview->get_window();
187  if (w) { // might not yet be initialized
188  gdk_window_invalidate_rect(w->gobj(), 0, true);
189  gdk_window_invalidate_rect(preset_treeview->get_window()->gobj(), 0, true);
190  }
191  return;
192  }
193  }
194  set_presets();
195  bool s = false;
196  if (machine.setting_is_preset()) {
198  if (pf && pf->is_mutable()) {
199  s = true;
200  }
201  }
202  actions.save_changes->set_sensitive(s);
203 }
204 
205 void PresetWindow::load_widget_pointers(Glib::RefPtr<gx_gui::GxBuilder> bld) {
206  bld->find_widget("close_preset", close_preset);
207  bld->find_widget("save_preset", save_preset);
208  bld->find_widget("new_preset_bank", new_preset_bank);
209  bld->find_widget("organize_presets", organize_presets);
210  bld->find_widget("online_preset", online_preset);
211  bld->find_widget_derived("bank_treeview", bank_treeview, sigc::ptr_fun(MyTreeView::create_from_builder));
212  bld->find_widget("bank_cellrenderer", bank_cellrenderer);
213  bld->find_widget_derived("preset_treeview", preset_treeview, sigc::ptr_fun(MyTreeView::create_from_builder));
214  bld->find_widget("preset_cellrenderer", preset_cellrenderer);
215  bld->find_widget("banks_combobox", banks_combobox);
216  bld->find_widget_derived("presets_target_treeview", presets_target_treeview, sigc::ptr_fun(MyTreeView::create_from_builder));
217  bld->find_widget("preset_title", preset_title);
218  bld->find_widget("presets_target_scrolledbox", presets_target_scrolledbox);
219  bld->find_widget("bank_column_edit", bank_column_edit);
220  bld->find_widget("bank_column_delete", bank_column_delete);
221  bld->find_widget("preset_column_edit", preset_column_edit);
222  bld->find_widget("preset_column_delete", preset_column_delete);
223  bld->find_widget("main_vpaned", main_vpaned);
224  bld->find_widget("preset_scrolledbox", preset_scrolledbox);
225 }
226 
227 static bool preset_button_press_idle(Gtk::Widget& w) {
228  w.grab_focus();
229  return false;
230 }
231 
232 bool PresetWindow::on_bank_query_tooltip(int x, int y, bool kb_tooltip, Glib::RefPtr<Gtk::Tooltip> tooltip) {
233  Gtk::TreeIter it;
234  if (!bank_treeview->get_tooltip_context_iter(x, y, kb_tooltip, it)) {
235  return false;
236  }
237  int tp = it->get_value(bank_col.tp);
239  return false;
240  }
241  Gtk::TreeModel::Path pt;
242  Gtk::TreeViewColumn *col;
243  int dx, dy;
244  if (!bank_treeview->get_path_at_pos(x, y, pt, col, dx, dy)) {
245  col = 0;
246  }
247  Glib::ustring nm = it->get_value(bank_col.name);
248  if (nm.empty()) {
249  return false;
250  }
251  gx_system::PresetFileGui *f = machine.get_bank_file(nm);
252  if (col == bank_treeview->get_column(0) || col == bank_treeview->get_column(1)) {
255  tooltip->set_text(_("damaged bank file; click to delete"));
256  } else if (f->get_flags() & gx_system::PRESET_FLAG_VERSIONDIFF) {
257  tooltip->set_text(
258  Glib::ustring::compose(_("wrong format version (is %1, need %2)\nclick to convert"),
259  f->get_header().version_string(),
261  } else if (f->get_flags() & gx_system::PRESET_FLAG_READONLY) {
262  tooltip->set_text(_("readonly bank, click to change to read-write"));
263  } else if (col == bank_treeview->get_column(0)){
264  tooltip->set_text(_("click to set to readonly"));
265  } else {
266  return false;
267  }
268  } else if (tp == gx_system::PresetFile::PRESET_FACTORY) {
269  tooltip->set_text(_("predefined factory preset bank"));
270  } else if (tp == gx_system::PresetFile::PRESET_SCRATCH) {
271  tooltip->set_text(_("scratch preset bank: changes will be persistent (without explicit saving)"));
272  } else {
273  return false;
274  }
275  } else if (col == bank_treeview->get_column(2)) {
276  if (f->get_flags()) {
277  return false;
278  }
279  tooltip->set_text(_("click to edit the bank name"));
280  } else if (col == bank_treeview->get_column(3)) {
281  if (f->get_flags()) {
282  return false;
283  }
284  tooltip->set_text(_("click to delete the bank"));
285  } else {
286  return false;
287  }
288  bank_treeview->set_tooltip_cell(tooltip, &pt, col, 0);
289  return true;
290 }
291 
292 void PresetWindow::on_preset_row_activated(const Gtk::TreePath& path, Gtk::TreeViewColumn* column) {
293  bool in_organize = actions.organize->get_active();
294  on_presets_close();
295  if (in_organize) {
296  preset_treeview->get_selection()->select(path);
297  }
298 }
299 
300 bool PresetWindow::on_preset_button_press(GdkEventButton *ev) {
301  if (ev->type == GDK_BUTTON_PRESS) {
302  Glib::signal_idle().connect(sigc::bind(sigc::ptr_fun(preset_button_press_idle), sigc::ref(*preset_treeview)));
303  }
304  return false;
305 }
306 
307 
308 void PresetWindow::on_preset_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection, int info, int timestamp) {
309  if (selection.get_target() == "application/x-guitarix-preset") {
310  Gtk::TreeModel::Path path;
311  Gtk::TreeViewColumn *focus_column;
312  preset_treeview->get_cursor(path, focus_column);
313  Glib::ustring data = pstore->get_iter(path)->get_value(pstore->col.name);
314  selection.set("application/x-guitarix-preset", data);
315  }
316 }
317 
318 void PresetWindow::on_bank_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection, int info, int timestamp) {
319  if (info != URILIST_TARGET && info != TEXT_TARGETS) {
320  return;
321  }
322  Gtk::TreeModel::Path path;
323  Gtk::TreeViewColumn *focus_column;
324  bank_treeview->get_cursor(path, focus_column);
325  Glib::RefPtr<Gio::File> f =
326  Gio::File::create_for_path(
327  machine.bank_get_filename(
328  bank_treeview->get_model()->get_iter(path)->get_value(bank_col.name)));
329  if (info == TEXT_TARGETS) {
330  selection.set_text(f->get_path());
331  } else {
332  std::vector<std::string> uris;
333  uris.push_back(f->get_uri());
334  selection.set_uris(uris);
335  }
336 }
337 
338 void PresetWindow::on_bank_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint timestamp) {
339  if (info != URILIST_TARGET) {
340  return;
341  }
342 #if false //gtk 2.22
343  bool is_move = context->get_selected_action() == Gdk::ACTION_MOVE;
344 #else
345  bool is_move = context->gobj()->action == GDK_ACTION_MOVE;
346 #endif
347  bool success = false;
348  std::vector<Glib::ustring> uris = data.get_uris();
349  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(bank_treeview->get_model());
350  for (std::vector<Glib::ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
351  gx_system::PresetFileGui *f = machine.bank_insert_uri(*i, is_move);
352  if (f) {
353  Gtk::TreeIter i = ls->prepend();
354  set_row_for_presetfile(i,f);
355  bank_treeview->set_cursor(ls->get_path(i));
356  bank_treeview->get_selection()->select(i);
357  success = true;
358  }
359  }
360  context->drag_finish(success, false, timestamp);
361 }
362 
363 Glib::ustring PresetWindow::get_combo_selection() {
364  Gtk::TreeIter idx = banks_combobox->get_active();
365  if (!idx) {
366  return "";
367  }
368  return idx->get_value(target_col.name);
369 }
370 
371 /*
372  ** dnd target
373  */
374 
375 void PresetWindow::target_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint timestamp) {
376  Glib::ustring bank = get_combo_selection();
377  if (bank.empty()) {
378  presets_target_treeview->signal_drag_data_received().emission_stop();
379  return;
380  }
381  gx_system::PresetFileGui& fl = *machine.get_bank_file(bank);
382  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(presets_target_treeview->get_model());
383  Glib::ustring srcnm = data.get_data_as_string();
384  Glib::ustring dstnm = srcnm;
385  int n = 1;
386  while (fl.has_entry(dstnm)) {
387  dstnm = srcnm + "-" + gx_system::to_string(n);
388  n += 1;
389  }
390  Glib::ustring src_bank = get_current_bank();
391  gx_system::PresetFileGui& pf = *machine.bank_get_file(src_bank);
392  if (src_bank == bank) {
393  gx_print_error("preset", "can't copy inside the same bank");
394  return;
395  }
396  Gtk::TreeModel::Path pt;
397  Gtk::TreeViewDropPosition dst;
398  if (!presets_target_treeview->get_dest_row_at_pos(x, y, pt, dst)) {
399  ls->append()->set_value(target_col.name, dstnm);
400  machine.pf_append(pf, srcnm, fl, dstnm);
401  } else {
402  Gtk::TreeIter it = ls->get_iter(pt);
403  if (dst == Gtk::TREE_VIEW_DROP_BEFORE || dst == Gtk::TREE_VIEW_DROP_INTO_OR_BEFORE) {
404  ls->insert(it)->set_value(target_col.name, dstnm);
405  machine.pf_insert_before(pf, srcnm, fl, it->get_value(target_col.name), dstnm);
406  } else { // gtk.TREE_VIEW_DROP_INTO_OR_AFTER, gtk.TREE_VIEW_DROP_AFTER
407  ls->insert_after(it)->set_value(target_col.name, dstnm);
408  machine.pf_insert_after(pf, srcnm, fl, it->get_value(target_col.name), dstnm);
409  }
410  }
411  if (context->get_action() == Gdk::ACTION_MOVE) {
412  Gtk::TreeModel::Path pt;
413  Gtk::TreeViewColumn *col;
414  preset_treeview->get_cursor(pt, col);
415  preset_row_del_conn.block();
416  pstore->erase(pstore->get_iter(pt));
417  preset_row_del_conn.unblock();
418  machine.erase_preset(pf, srcnm);
419  }
420  if (src_bank == bank) {
421  on_bank_changed();
422  }
423 }
424 
425 bool PresetWindow::on_target_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint timestamp) {
426  Gtk::Widget *source_widget = Gtk::Widget::drag_get_source_widget(context);
427  if (source_widget != preset_treeview || get_combo_selection().empty()) {
428  context->drag_status((Gdk::DragAction)0, timestamp);
429  return true;
430  }
431  presets_target_treeview->on_drag_motion(context, x, y, timestamp);
432  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
433  int tp = it->get_value(bank_col.tp);
434  Glib::ustring nm = it->get_value(bank_col.name);
436  get_combo_selection() == nm) {
437  context->drag_status(Gdk::ACTION_COPY, timestamp);
438  }
439  return true;
440 }
441 
442 void PresetWindow::reload_combo() {
443  Glib::ustring old = get_combo_selection();
444  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(banks_combobox->get_model());
445  ls->clear();
446  int n = 0;
447  int nn = -1;
448  for (gx_engine::bank_iterator i = machine.bank_begin(); i != machine.bank_end(); ++i) {
449  int tp = i->get_type();
451  continue;
452  }
453  if (i->get_flags()) {
454  continue;
455  }
456  Glib::ustring s = i->get_name();
457  ls->append()->set_value(bank_col.name, s);
458  if (s == old) {
459  nn = n;
460  }
461  n += 1;
462  }
463  banks_combobox->set_active(nn);
464 }
465 
466 void PresetWindow::on_preset_combo_changed() {
467  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(presets_target_treeview->get_model());
468  ls->clear();
469  Glib::ustring nm = get_combo_selection();
470  if (nm.empty()) {
471  return;
472  }
473  gx_system::PresetFileGui& f = *machine.get_bank_file(nm);
474  for (gx_system::PresetFile::iterator i = f.begin(); i != f.end(); ++i) {
475  ls->append()->set_value(bank_col.name, i->name);
476  }
477 }
478 
479 void PresetWindow::reload_target() {
480  on_preset_combo_changed();
481 }
482 
483 /*
484  ** name edit
485  */
486 
487 bool PresetWindow::select_func(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreePath& path, bool path_currently_selected) {
488  Glib::ustring s = model->get_iter(path)->get_value(bank_col.name);
489  if (s.empty()) {
490  return false;
491  }
492  return true;
493 }
494 
495 void PresetWindow::on_editing_started(const Gtk::CellEditable* edit, const Glib::ustring& path, Glib::RefPtr<Gtk::TreeModel>& model) {
496  Glib::ustring s = model->get_iter(path)->get_value(bank_col.name);
497  if (s.empty()) {
498  dynamic_cast<Gtk::Entry*>(const_cast<Gtk::CellEditable*>(edit))->set_text("");
499  } else {
500  dynamic_cast<Gtk::Entry*>(const_cast<Gtk::CellEditable*>(edit))->set_text(s);
501  }
502  dynamic_cast<Gtk::Window*>(main_vpaned->get_toplevel())->remove_accel_group(actions.accels);
503 }
504 
505 bool PresetWindow::edit_cell(const Gtk::TreeModel::Path pt, Gtk::TreeViewColumn& col, Gtk::CellRenderer& cell) {
506  dynamic_cast<Gtk::CellRendererText*>(&cell)->property_editable().set_value(true);
507  col.get_tree_view()->set_cursor(pt, col, true);
508  return false;
509 }
510 
511 void PresetWindow::reset_edit(Gtk::TreeViewColumn& col) {
512  if (edit_iter) {
513  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(col.get_tree_view()->get_model());
514  ls->erase(edit_iter);
515  edit_iter = ls->children().end();
516  }
517  Gtk::CellRendererText& cell = *dynamic_cast<Gtk::CellRendererText*>(col.get_first_cell_renderer());
518  cell.property_editable().set_value(false);
519  col.set_min_width(0);
520  col.queue_resize();
521  in_edit = false;
522  dynamic_cast<Gtk::Window*>(main_vpaned->get_toplevel())->add_accel_group(actions.accels);
523 }
524 
525 void PresetWindow::on_edit_canceled(Gtk::TreeViewColumn *col) {
526  reset_edit(*col);
527 }
528 
529 void PresetWindow::start_edit(const Gtk::TreeModel::Path& pt, Gtk::TreeViewColumn& col, Gtk::CellRenderer& cell) {
530  col.set_min_width(100);
531  Glib::signal_idle().connect(
532  sigc::bind(sigc::mem_fun(*this, &PresetWindow::edit_cell),
533  pt, sigc::ref(col), sigc::ref(cell)));
534 }
535 
536 /*
537  ** list of banks
538  */
539 
540 void PresetWindow::highlight_current_bank(Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator& iter) {
541  Glib::ustring t = iter->get_value(bank_col.name);
542  if (t.empty()) {
543  return;
544  }
545  Gtk::CellRendererText *tc = dynamic_cast<Gtk::CellRendererText*>(cell);
546  if (machine.setting_is_preset() && t == machine.get_current_bank()) {
547  tc->property_foreground().set_value("#f00");
548  } else{
549  tc->property_foreground_set().set_value(false);
550  }
551  int n = machine.bank_size() - *bank_treeview->get_model()->get_path(iter).begin();
553  n -= 1;
554  }
555  if (n > 26) {
556  t = " " + t;
557  } else {
558  t = Glib::ustring::compose("%1: %2", char('A'+n), t);
559  }
560  cell->set_property("text", t);
561 }
562 
563 Glib::ustring PresetWindow::get_current_bank() {
564  Gtk::TreeIter it = get_current_bank_iter();
565  if (!it) {
566  return "";
567  }
568  return it->get_value(bank_col.name);
569 }
570 
571 bool PresetWindow::run_message_dialog(Gtk::Widget& w, const Glib::ustring& msg) {
572  Gtk::MessageDialog d(*dynamic_cast<Gtk::Window*>(w.get_toplevel()), msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
573  d.set_position(Gtk::WIN_POS_MOUSE);
574  return d.run() == Gtk::RESPONSE_OK;
575 }
576 
577 bool PresetWindow::on_bank_button_release(GdkEventButton *ev) {
578  // edit bank name / delete bank
579  Gtk::TreeModel::Path pt;
580  Gtk::TreeViewColumn *col;
581  int dx, dy;
582  if (!bank_treeview->get_path_at_pos(ev->x, ev->y, pt, col, dx, dy)) {
583  return false;
584  }
585  Gtk::TreeModel::Path path;
586  Gtk::TreeViewColumn *focus_column;
587  bank_treeview->get_cursor(path, focus_column);
588  if (col != focus_column || pt != path) {
589  return false;
590  }
591  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(bank_treeview->get_model());
592  Gtk::TreeModel::iterator it = ls->get_iter(pt);
593  Glib::ustring nm = it->get_value(bank_col.name);
594  int tp = it->get_value(bank_col.tp);
595  if (col == bank_treeview->get_column(0)) {
597  int flags = machine.get_bank_file(nm)->get_flags();
598  gx_system::PresetFileGui *f = machine.get_bank_file(nm);
599  if (flags == 0 && tp == gx_system::PresetFile::PRESET_FILE) {
600  /*if (run_message_dialog(*bank_treeview, "set bank " + nm + " to readonly?")) {*/
602  reload_banks(nm);
603  } else if (flags == gx_system::PRESET_FLAG_VERSIONDIFF) {
604  if (run_message_dialog(*bank_treeview, "convert bank " + nm + " to new version?")) {
605  if (machine.convert_preset(*f)) {
606  reload_banks(nm);
607  }
608  }
609  } else if (flags == gx_system::PRESET_FLAG_READONLY) {
610  /*if (run_message_dialog(*bank_treeview, "set bank " + nm + " to read/write?")) {*/
612  reload_banks(nm);
614  if (run_message_dialog(*bank_treeview, "convert readonly bank " + nm + " to new version?")) {
615  if (machine.convert_preset(*f)) {
616  reload_banks(nm);
617  }
618  }
619  } else if (flags & gx_system::PRESET_FLAG_INVALID) {
620  if (run_message_dialog(
621  *bank_treeview, "delete damaged bank " + nm + "?"
622  " Export it before deleting and ask in the"
623  " guitarix online forum if you want to try to repair it!")) {
624  machine.bank_remove(nm);
625  reload_banks(nm);
626  }
627  }
628  }
629  return false;
630  }
631  if (tp != gx_system::PresetFile::PRESET_FILE || machine.get_bank_file(nm)->get_flags()) {
632  return false;
633  }
634  if (col == bank_treeview->get_column(2)) {
635  col = bank_treeview->get_column(1);
636  start_edit(pt, *col, *col->get_first_cell_renderer());
637  } else if (col == bank_treeview->get_column(3)) {
638  Gtk::MessageDialog d(*dynamic_cast<Gtk::Window*>(bank_treeview->get_toplevel()), "delete bank " + nm + "?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
639  d.set_position(Gtk::WIN_POS_MOUSE);
640  if (d.run() == Gtk::RESPONSE_OK) {
641  bank_row_del_conn.block();
642  ls->erase(it);
643  bank_row_del_conn.unblock();
644  machine.bank_remove(nm);
645  reload_combo();
646  if (!machine.setting_is_preset()) { // if current bank was removed
647  actions.save_changes->set_sensitive(false);
648  }
649  }
650  }
651  return false;
652 }
653 
654 void PresetWindow::on_bank_edited(const Glib::ustring& path, const Glib::ustring& newtext, Gtk::TreeView* w) {
655  Gtk::TreeIter sel = w->get_model()->get_iter(path);
656  Glib::ustring oldname = sel->get_value(bank_col.name);
657  Glib::ustring newname = newtext;
658  gx_system::strip(newname);
659  if (newname.empty() || newname == oldname) {
660  Gtk::TreeViewColumn *p = w->get_column(1);
661  reset_edit(*p);
662  return;
663  }
664  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(banks_combobox->get_model());
665  if (edit_iter) {
666  gx_system::PresetFileGui *f = machine.bank_insert_new(newname);
667  if (f) {
668  ls->prepend()->set_value(target_col.name, f->get_name());
669  edit_iter = ls->children().end();
670  set_row_for_presetfile(sel, f);
671  w->get_selection()->select(sel);
672  }
673  } else {
674  machine.rename_bank(oldname, newname);
675  Gtk::TreeNodeChildren ch = ls->children();
676  for (Gtk::TreeIter it = ch.begin(); it != ch.end(); ++it) {
677  if (it->get_value(bank_col.name) == oldname) {
678  it->set_value(bank_col.name, newname);
679  }
680  }
681  w->get_model()->get_iter(path)->set_value(bank_col.name, newname);
682  }
683  Gtk::TreeViewColumn *p = w->get_column(1);
684  reset_edit(*p);
685 }
686 
687 bool PresetWindow::is_row_separator(const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::iterator& iter) {
688  return iter->get_value(bank_col.tp) == gx_system::PresetFile::PRESET_SEP;
689 }
690 
691 void PresetWindow::on_new_bank() {
692  Glib::RefPtr<Gtk::ListStore> m = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(bank_treeview->get_model());
693  edit_iter = m->prepend();
694  edit_iter->set_value(bank_col.tp, static_cast<int>(gx_system::PresetFile::PRESET_FILE));
695  in_edit = true;
696  start_edit(m->get_path(edit_iter), *bank_treeview->get_column(1), *bank_cellrenderer);
697 }
698 
699 #ifdef HAVE_WEBKIT
700 
701 bool PresetWindow::insertRequested(const char *ur, gpointer data)
702 {
703  PresetWindow& self = *reinterpret_cast<PresetWindow*>(data);
704  const char *file_name = strrchr( ur, '/' ) + 1;
705  const gchar* dest = g_strdup_printf("file:///tmp/%s",file_name);
706  //fprintf(stderr,"insert %s\n",dest);
707  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(self.bank_treeview->get_model());
708  gx_system::PresetFileGui *f = self.machine.bank_insert_uri(dest, false);
709  if (f) {
710  Gtk::TreeIter i = ls->prepend();
711  self.set_row_for_presetfile(i,f);
712  self.bank_treeview->set_cursor(ls->get_path(i));
713  self.bank_treeview->get_selection()->select(i);
714  }
715  return TRUE;
716 }
717 
718 void PresetWindow::download_status(GObject* object, GParamSpec* pspec, gpointer data) {
719  WebKitDownload *download;
720  WebKitDownloadStatus status;
721  const char *uri;
722 
723  download = WEBKIT_DOWNLOAD(object);
724  status = webkit_download_get_status(download);
725  uri = webkit_download_get_uri(download);
726 
727  switch (status) {
728  case WEBKIT_DOWNLOAD_STATUS_ERROR:
729  gx_print_error(_("Download Status"),
730  boost::format(_("ERROR download %1%")) % uri);
731  break;
732  case WEBKIT_DOWNLOAD_STATUS_CREATED:
733  //printf("download created: %s\n", uri);
734  break;
735  case WEBKIT_DOWNLOAD_STATUS_STARTED:
736  //printf("download started: %s\n", uri);
737  break;
738  case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
739  gx_print_info(_("Download Status"),
740  boost::format(_("download cancelled %1%")) % uri);
741  break;
742  case WEBKIT_DOWNLOAD_STATUS_FINISHED:
743  gx_print_info(_("Download Status"),
744  boost::format(_("download finished %1%")) % uri);
745  insertRequested(uri, data);
746  break;
747  default:
748  g_assert_not_reached();
749  }
750 }
751 
752 bool PresetWindow::downloadRequested(WebKitWebView* webView, WebKitDownload *download, gpointer data)
753 {
754  const char *ur = webkit_download_get_uri (download);
755  const char *file_name = strrchr( ur, '/' ) + 1;
756  const gchar* dest = g_strdup_printf("file:///tmp/%s",file_name);
757  webkit_download_set_destination_uri(download, dest);
758  g_signal_connect(download, "notify::status", G_CALLBACK(download_status), data);
759  return TRUE;
760 }
761 
762 bool PresetWindow::uploadRequested(WebKitWebView* webView, WebKitFileChooserRequest *request,gpointer data )
763 {
764  Gtk::FileChooserDialog d( "Select upload file");
765  d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
766  d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
767  d.add_shortcut_folder(string(getenv("HOME")) + string("/.config/guitarix/bamks"));
768  Gtk::FileFilter banks;
769  banks.set_name("Bank Files");
770  banks.add_pattern("*.gx");
771  d.add_filter(banks);
772  Gtk::FileFilter all;
773  all.add_pattern("*");
774  all.set_name("All Files");
775  d.add_filter(all);
776  d.set_current_folder(string(getenv("HOME")) + string("/.config/guitarix/banks"));
777 
778  if (d.run() != Gtk::RESPONSE_OK) {
779  return FALSE;
780  }
781  Glib::ustring filename = d.get_filename();
782  const gchar* f[2] = {filename.c_str(),0};
783  webkit_file_chooser_request_select_files (request, f);
784  return TRUE;
785 }
786 
787 void PresetWindow::show_online_preset() {
788 
789  Gtk::Window *window = new Gtk::Window();
790  Gtk::ScrolledWindow *scrollbox = Gtk::manage(new Gtk::ScrolledWindow());
791  scrollbox->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
792  window->set_default_size( 800, 500 );
793  WebKitWebView * web_view = WEBKIT_WEB_VIEW( webkit_web_view_new() );
794  WebKitWebSettings *settings = webkit_web_settings_new ();
795  g_object_set (G_OBJECT(settings), "enable-offline-web-application-cache", TRUE, NULL);
796  g_object_set (G_OBJECT(settings), "enable-page-cache", TRUE, NULL);
797  webkit_web_view_set_settings (WEBKIT_WEB_VIEW(web_view), settings);
798 
799 
800  scrollbox->add(*Gtk::manage(( Glib::wrap(GTK_WIDGET(web_view )))));
801  window->add(*Gtk::manage(scrollbox));
802  webkit_web_view_load_uri(web_view, "https://api.musical-artifacts.com/guitarix-presets/");
803  g_signal_connect(G_OBJECT (web_view), "download-requested", G_CALLBACK(downloadRequested), this);
804  g_signal_connect(G_OBJECT (web_view), "run-file-chooser", G_CALLBACK(uploadRequested), this);
805  window->show_all();
806 }
807 
808 void PresetWindow::on_online_preset() {
809  Glib::signal_idle().connect_once(sigc::mem_fun(*this, &PresetWindow::show_online_preset));
810 }
811 
812 #endif
813 
814 bool PresetWindow::on_bank_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint timestamp) {
815  Gtk::Widget *source_widget = Gtk::Widget::drag_get_source_widget(context);
816  if (!source_widget) {
817  // URI from other application
818  Gdk::DragAction a;
819  if (context->get_suggested_action() == Gdk::ACTION_MOVE) {
820  a = context->get_suggested_action();
821  } else {
822  a = Gdk::ACTION_COPY;
823  }
824  context->drag_status(a, timestamp);
825  } else if (source_widget != bank_treeview) {
826  // other window
827  context->drag_status((Gdk::DragAction)0, timestamp);
828  } else {
829  // reorder
830  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
831  if (!it) {
832  return true;
833  }
834  int tp = it->get_value(bank_col.tp);
836  context->drag_status((Gdk::DragAction)0, timestamp);
837  return true;
838  }
839  Gtk::TreeModel::Path pt;
840  Gtk::TreeViewDropPosition dst;
841  if (bank_treeview->get_dest_row_at_pos(x, y, pt, dst)) {
842  tp = bank_treeview->get_model()->get_iter(pt)->get_value(bank_col.tp);
844  context->drag_status((Gdk::DragAction)0, timestamp);
845  return true;
846  }
847  }
848  bank_treeview->on_drag_motion(context, x, y, timestamp);
849  context->drag_status(Gdk::ACTION_MOVE, timestamp);
850  }
851  return true;
852 }
853 
854 void PresetWindow::on_bank_changed() {
855  preset_row_del_conn.block();
856  if (in_edit) {
857  pstore->prepend();
858  }
859  pstore->clear();
860  preset_row_del_conn.unblock();
861  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
862  if (!it) {
863  in_current_preset = false;
864  return;
865  }
866  Glib::ustring nm = it->get_value(bank_col.name);
867  preset_title->set_text(nm);
868  in_current_preset = (nm == machine.get_current_bank());
869  Gtk::TreeIter i;
870  gx_system::PresetFileGui& ll = *machine.get_bank_file(nm);
872  ((ll.get_flags() & gx_system::PRESET_FLAG_READONLY) && !actions.organize->get_active())) {
873  preset_treeview->unset_rows_drag_source();
874  } else {
875  preset_treeview->unset_rows_drag_source(); //FIXME: needed?
876  preset_treeview->set_reorderable(true);
877  std::vector<Gtk::TargetEntry> listTargets2;
878  listTargets2.push_back(Gtk::TargetEntry("GTK_TREE_MODEL_ROW", Gtk::TARGET_SAME_WIDGET, 0));
879  listTargets2.push_back(Gtk::TargetEntry("application/x-guitarix-preset", Gtk::TARGET_SAME_APP, 1));
880  preset_treeview->enable_model_drag_source(listTargets2, Gdk::BUTTON1_MASK, Gdk::ACTION_COPY|Gdk::ACTION_MOVE);
881  }
882  bool modifiable = ll.is_mutable();
883  for (gx_system::PresetFile::iterator s = ll.begin(); s != ll.end(); ++s) {
884  i = pstore->append();
885  i->set_value(pstore->col.name, s->name);
886  if (modifiable) {
887  i->set_value(pstore->col.edit_pb, pb_edit);
888  i->set_value(pstore->col.del_pb, pb_del);
889  }
890  if (in_current_preset && s->name == machine.get_current_name()) {
891  if (preset_treeview->get_mapped()) {
892  preset_treeview->scroll_to_row(pstore->get_path(i));
893  }
894  }
895  }
896  if (modifiable) {
897  i = pstore->append();
898  }
899 }
900 
901 void PresetWindow::set_row_for_presetfile(Gtk::TreeIter i, gx_system::PresetFileGui *f) {
902  i->set_value(bank_col.name, f->get_name());
904  i->set_value(bank_col.type_pb, pb_del);
905  } else if (f->get_flags() & gx_system::PRESET_FLAG_VERSIONDIFF) {
906  i->set_value(bank_col.type_pb, pb_versiondiff);
907  } else if (f->get_flags() & gx_system::PRESET_FLAG_READONLY) {
908  i->set_value(bank_col.type_pb, pb_readonly);
909  }
910  int tp = f->get_type();
911  i->set_value(bank_col.tp, tp);
913  i->set_value(bank_col.type_pb, pb_scratch);
914  } else if (tp == gx_system::PresetFile::PRESET_FACTORY) {
915  i->set_value(bank_col.type_pb, pb_factory);
916  } else if (f->is_mutable() || f->get_flags() & gx_system::PRESET_FLAG_VERSIONDIFF) {
917  i->set_value(bank_col.edit_pb, pb_edit);
918  i->set_value(bank_col.del_pb, pb_del);
919  }
920 }
921 
922 void PresetWindow::reload_banks(const Glib::ustring& sel_bank) {
923  preset_row_del_conn.block();
924  pstore->clear();
925  preset_row_del_conn.unblock();
926  Glib::RefPtr<Gtk::ListStore> ls = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(bank_treeview->get_model());
927  bank_row_del_conn.block();
928  ls->clear();
929  bank_row_del_conn.unblock();
930  Gtk::TreeIter i;
931  int in_factory = false;
932  for (gx_engine::bank_iterator v = machine.bank_begin(); v != machine.bank_end(); ++v) {
933  if (!in_factory && v->get_type() == gx_system::PresetFile::PRESET_FACTORY) {
934  i = ls->append();
935  i->set_value(bank_col.tp, static_cast<int>(gx_system::PresetFile::PRESET_SEP));
936  in_factory = true;
937  }
938  i = ls->append();
939  set_row_for_presetfile(i, *v);
940  if (v->get_name() == sel_bank) {
941  bank_treeview->get_selection()->select(i);
942  }
943  }
944  reload_combo();
945 }
946 
947 void PresetWindow::set_presets() {
948  reload_banks(machine.get_current_bank());
949 }
950 
951 void PresetWindow::on_bank_reordered(const Gtk::TreeModel::Path& path) {
952  Glib::RefPtr<Gtk::TreeModel> ls = bank_treeview->get_model();
953  Gtk::TreeModel::Children ch = ls->children();
954  std::vector<Glib::ustring> l;
955  for (Gtk::TreeIter i = ch.begin(); i != ch.end(); ++i) {
956  int tp = i->get_value(bank_col.tp);
957  Glib::ustring nm = i->get_value(bank_col.name);
959  l.push_back(nm);
960  }
961  }
962  machine.bank_reorder(l);
963 }
964 
965 /*
966  ** list of presets
967  */
968 
969 void PresetWindow::text_func(Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator& iter) {
970  Glib::ustring val = iter->get_value(pstore->col.name);
971  Glib::ustring t = val;
972 #if false // gtk 2.24
973  if (t.empty() && !cell->property_editing().get_value()) {
974  } //to make indent happy (remove)
975 #else
976  gboolean editing;
977  g_object_get(cell->gobj(), "editing", &editing, NULL);
978  if (t.empty() && !editing) {
979 #endif
980  t = "<new>";
981  } else if (in_current_preset) {
982  int n = *pstore->get_path(iter).begin();
983  if (n > 9) {
984  t = " " + t;
985  } else {
986  t = Glib::ustring::compose("%1: %2", (n == 9 ? 0 : n+1), t);
987  }
988  }
989  cell->set_property("text", t);
990  Gtk::CellRendererText *tc = dynamic_cast<Gtk::CellRendererText*>(cell);
991  if (in_current_preset && machine.setting_is_preset() && val == machine.get_current_name()) {
992  tc->property_foreground().set_value("#f00");
993  } else{
994  tc->property_foreground_set().set_value(false);
995  }
996 }
997 
998 bool PresetWindow::on_preset_button_release(GdkEventButton *ev) {
999  Gtk::TreeModel::Path pt;
1000  Gtk::TreeViewColumn *col;
1001  int dx, dy;
1002  if (!preset_treeview->get_path_at_pos(ev->x, ev->y, pt, col, dx, dy)) {
1003  return false;
1004  }
1005  Gtk::TreeModel::Path path;
1006  Gtk::TreeViewColumn *focus_column;
1007  preset_treeview->get_cursor(path, focus_column);
1008  if (col != focus_column || !path || pt != path) {
1009  return false;
1010  }
1011  Gtk::TreeIter bank_iter = get_current_bank_iter();
1012  int tp = bank_iter->get_value(bank_col.tp);
1013  if ((tp != gx_system::PresetFile::PRESET_SCRATCH && tp != gx_system::PresetFile::PRESET_FILE) || machine.get_bank_file(bank_iter->get_value(bank_col.name))->get_flags()) {
1014  return false;
1015  }
1016  if (col == preset_treeview->get_column(1)) {
1017  col = preset_treeview->get_column(0);
1018  start_edit(pt, *col, *col->get_first_cell_renderer());
1019  } else if (col == preset_treeview->get_column(2)) {
1020  Glib::ustring nm = pstore->get_iter(pt)->get_value(pstore->col.name);
1021  Gtk::MessageDialog d(*dynamic_cast<Gtk::Window*>(preset_treeview->get_toplevel()), Glib::ustring::compose("delete preset %1?", nm), false,
1022  Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
1023  d.set_position(Gtk::WIN_POS_MOUSE);
1024  if (d.run() == Gtk::RESPONSE_OK) {
1025  preset_row_del_conn.block();
1026  pstore->erase(pstore->get_iter(pt));
1027  preset_row_del_conn.unblock();
1028  machine.erase_preset(*machine.get_bank_file(bank_iter->get_value(bank_col.name)), nm);
1029  reload_target();
1030  }
1031  }
1032  return false;
1033 }
1034 
1035 void PresetWindow::on_preset_edited(const Glib::ustring& path, const Glib::ustring& newtext) {
1036  Gtk::TreeIter it = pstore->get_iter(path);
1037  Glib::ustring oldname = it->get_value(pstore->col.name);
1038  Glib::ustring newname = newtext;
1039  gx_system::strip(newname);
1040  if (newname.empty() || newname == oldname) {
1041  reset_edit(*preset_treeview->get_column(0));
1042  return;
1043  }
1044  // vowel mutation lead to a Glib::markup error when building the menu action,
1045  // so check for it and avoid them
1046  if (newname.find_first_of("ÜüÖöÄä") != Glib::ustring::npos) {
1047  gx_print_error("PresetWindow", "Vowel mutation isn't allowed in preset names, please choose a name without (ÜüÖöÄä)");
1048  reset_edit(*preset_treeview->get_column(0));
1049  return;
1050  }
1051  gx_system::PresetFileGui& fl = *machine.get_bank_file(get_current_bank());
1052  Glib::ustring t = newname;
1053  int n = 1;
1054  while (fl.has_entry(newname)) {
1055  newname = Glib::ustring::compose("%1-%2", t, n);
1056  n += 1;
1057  }
1058  it->set_value(pstore->col.name, newname);
1059  it->set_value(pstore->col.edit_pb, pb_edit);
1060  it->set_value(pstore->col.del_pb, pb_del);
1061  if (oldname.empty()) {
1062  // check if current preset is scratch and needs to be saved
1063  if (!machine.get_current_bank().empty()) {
1064  gx_system::PresetFileGui *cpf = machine.get_bank_file(machine.get_current_bank());
1065  if (cpf && cpf->has_entry(machine.get_current_name())) {
1066  if (cpf->get_type() == gx_system::PresetFile::PRESET_SCRATCH && cpf->is_mutable()) {
1067  machine.pf_save(*cpf, machine.get_current_name());
1068  }
1069  }
1070  }
1071  pstore->append();
1072  machine.pf_save(fl, newname);
1073  } else {
1074  machine.rename_preset(fl, oldname, newname);
1075  }
1076  reload_target();
1077  reset_edit(*preset_treeview->get_column(0));
1078 }
1079 
1080 void PresetWindow::on_cursor_changed() {
1081  if (in_edit) {
1082  return;
1083  }
1084  Gtk::TreeModel::Path path;
1085  Gtk::TreeViewColumn *focus_column;
1086  preset_treeview->get_cursor(path, focus_column);
1087  if (!pstore->get_iter(path)->get_value(pstore->col.name).empty()) {
1088  return;
1089  }
1090  in_edit = true;
1091  start_edit(path, *preset_treeview->get_column(0), *preset_cellrenderer);
1092 }
1093 
1094 bool PresetWindow::on_preset_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint timestamp) {
1095  if (Gtk::Widget::drag_get_source_widget(context) == preset_treeview) {
1096  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
1097  bool ro = it && (machine.get_bank_file(it->get_value(bank_col.name))->get_flags() & gx_system::PRESET_FLAG_READONLY);
1098  if (!ro) {
1099  preset_treeview->on_drag_motion(context, x, y, timestamp);
1100  Gtk::TreeModel::Path pt;
1101  Gtk::TreeViewDropPosition dst;
1102  if (preset_treeview->get_dest_row_at_pos(x, y, pt, dst)) {
1103  if (dst == Gtk::TREE_VIEW_DROP_BEFORE ||
1104  (dst == Gtk::TREE_VIEW_DROP_AFTER &&
1105  !pstore->get_iter(pt)->get_value(pstore->col.name).empty())) {
1106  context->drag_status(Gdk::ACTION_MOVE, timestamp);
1107  return true;
1108  }
1109  }
1110  }
1111  }
1112  context->drag_status((Gdk::DragAction)0, timestamp);
1113  return true;
1114 }
1115 
1116 void PresetWindow::on_preset_reordered(const Gtk::TreeModel::Path& path) {
1117  // save changed order to file
1118  Gtk::TreeModel::Children ch = pstore->children();
1119  std::vector<Glib::ustring> l;
1120  for (Gtk::TreeIter i = ch.begin(); i != ch.end(); ++i) {
1121  Glib::ustring s = i->get_value(pstore->col.name);
1122  if (!s.empty()) {
1123  l.push_back(s);
1124  }
1125  }
1126  machine.reorder_preset(*machine.get_bank_file(get_current_bank()), l);
1127  reload_target();
1128 }
1129 
1130 void PresetWindow::autosize() {
1131  if (bank_treeview->get_mapped()) {
1132  bank_treeview->columns_autosize();
1133  preset_treeview->columns_autosize();
1134  }
1135 }
1136 
1137 void PresetWindow::on_organize() {
1138  bool v = organize_presets->get_active();
1139  bank_column_edit->set_visible(v);
1140  bank_column_delete->set_visible(v);
1141  preset_column_edit->set_visible(v);
1142  preset_column_delete->set_visible(v);
1143  Glib::RefPtr<Gtk::TreeSelection> sel = preset_treeview->get_selection();
1144  if (v) {
1145  actions.presets->set_active(true);
1146  sel->set_mode(Gtk::SELECTION_NONE);
1147  banks_combobox->set_active(-1);
1148  banks_combobox->show();
1149  presets_target_scrolledbox->show();
1150  actions.save_changes->set_sensitive(false);
1151  } else {
1152  sel->set_mode(Gtk::SELECTION_BROWSE);
1153  banks_combobox->hide();
1154  presets_target_scrolledbox->hide();
1155  if (machine.setting_is_preset()) {
1156  if (machine.get_bank_file(machine.get_current_bank())->is_mutable()) {
1157  actions.save_changes->set_sensitive(true);
1158  }
1159  }
1160  }
1161  on_bank_changed(); // reload for DnD adjustment of readonly banks
1162  autosize();
1163 }
1164 
1165 void PresetWindow::on_presets_close() {
1166  actions.presets->set_active(false); // FIXME
1167 }
1168 
1169 /*
1170  ** preset window
1171  */
1172 
1173 bool PresetWindow::animate_preset_show() {
1174  vpaned_pos -= vpaned_step;
1175  if (vpaned_pos <= vpaned_target) {
1176  main_vpaned->set_position(vpaned_target);
1177  gx_gui::child_set_property(*main_vpaned, *preset_scrolledbox, "shrink", false);
1178  Gtk::TreeIter it = get_current_bank_iter();
1179  if (it) {
1180  bank_treeview->scroll_to_row(bank_treeview->get_model()->get_path(it));
1181  }
1182  return false;
1183  }
1184  main_vpaned->set_position(vpaned_pos);
1185  return true;
1186 }
1187 
1188 bool PresetWindow::animate_preset_hide() {
1189  vpaned_pos += vpaned_step;
1190  if (vpaned_pos >= vpaned_target) {
1191  preset_scrolledbox->hide();
1192  return false;
1193  }
1194  main_vpaned->set_position(vpaned_pos);
1195  return true;
1196 }
1197 
1198 void PresetWindow::on_preset_changed() {
1199  if (actions.organize->get_active()) {
1200  return;
1201  }
1202  Glib::ustring bank;
1203  Glib::ustring name;
1204  Gtk::TreeIter it = bank_treeview->get_selection()->get_selected();
1205  if (!it) {
1206  return;
1207  }
1208  bank = it->get_value(bank_col.name);
1209  it = preset_treeview->get_selection()->get_selected();
1210  if (!it) {
1211  return;
1212  }
1213  name = it->get_value(pstore->col.name);
1214  bool is_scratch = false;
1215  gx_system::PresetFileGui *cpf = 0;
1216  if (!machine.get_current_bank().empty()) {
1217  cpf = machine.get_bank_file(machine.get_current_bank());
1218  if (cpf && cpf->has_entry(machine.get_current_name())) {
1219  is_scratch = (cpf->get_type() == gx_system::PresetFile::PRESET_SCRATCH);
1220  }
1221  }
1222  if (is_scratch) {
1223  if (bank == machine.get_current_bank() && name == machine.get_current_name()) {
1224  machine.pf_save(*cpf, machine.get_current_name());
1225  // no reload necessary
1226  return;
1227  }
1228  }
1229  in_current_preset = true;
1230  cpf = machine.get_bank_file(bank);
1231  machine.load_preset(cpf, name);
1232  actions.save_changes->set_sensitive(cpf && cpf->is_mutable());
1233 }
1234 
1235 void PresetWindow::on_preset_save() {
1236  if (!machine.setting_is_preset()) {
1237  return;
1238  }
1239  gx_system::PresetFileGui *pf = machine.get_bank_file(machine.get_current_bank());
1240  if (!pf->is_mutable()) {
1241  return;
1242  }
1243  machine.pf_save(*pf, machine.get_current_name());
1244 }
1245 
1246 void PresetWindow::display_paned(bool show_preset, int paned_child_height) {
1247  if (preset_scrolledbox->get_parent() == main_vpaned) {
1248  vpaned_pos = main_vpaned->get_allocation().get_height();
1249  int w, h;
1250  main_vpaned->get_handle_window()->get_size(w, h);
1251  vpaned_target = vpaned_pos - paned_child_height - h;
1252  main_vpaned->set_position(vpaned_target);
1253  gx_gui::child_set_property(*main_vpaned, *preset_scrolledbox, "shrink", false);
1254  }
1255  preset_scrolledbox->show();
1256  if (!show_preset || !in_current_preset) {
1257  return;
1258  }
1259  on_map_conn.disconnect();
1260  // make the current entry in the preset list window
1261  // visible (in case it's outside the displayed range).
1262  // apparently only works after the window is mapped
1263  // and some size calculations are done, so put it into
1264  // an idle handler.
1265  Gtk::TreeIter it = get_current_bank_iter();
1266  if (it) {
1267  Glib::signal_idle().connect_once(
1268  sigc::bind(
1269  sigc::mem_fun1(bank_treeview, &MyTreeView::scroll_to_row),
1270  bank_treeview->get_model()->get_path(it)));
1271  }
1272  Gtk::TreeNodeChildren ch = pstore->children();
1273  for (it = ch.begin(); it != ch.end(); ++it) {
1274  if (it->get_value(pstore->col.name) == machine.get_current_name()) {
1275  Glib::signal_idle().connect_once(
1276  sigc::bind(
1277  sigc::mem_fun1(*preset_treeview, &MyTreeView::scroll_to_row),
1278  pstore->get_path(it)));
1279  break;
1280  }
1281  }
1282 }
1283 
1284 void PresetWindow::on_preset_select(bool v, bool animated, int paned_child_height) {
1285  static bool first_time = true;
1286  if (first_time) {
1287  //FIXME needed to fix first time display height, not clear why
1288  paned_child_height += 1;
1289  first_time = false;
1290  }
1291  on_map_conn.disconnect();
1292  bool is_mapped = main_vpaned->get_toplevel()->get_mapped();
1293  bool rack_visible = actions.show_rack->get_active();
1294  if (v) {
1295  if (machine.bank_check_reparse()) {
1296  set_presets();
1297  } else if (!get_current_bank_iter()) {
1298  Glib::ustring bank = machine.get_current_bank();
1299  if (!bank.empty()) {
1300  reload_banks(bank);
1301  }
1302  }
1303  autosize();
1304  Gtk::TreeIter it = get_current_bank_iter();
1305  if (it && animated && is_mapped) {
1306  bank_treeview->scroll_to_row(bank_treeview->get_model()->get_path(it));
1307  }
1308  if (!is_mapped) {
1309  // don't have widget height to calculate paned separator
1310  // position before window is mapped
1311  on_map_conn = main_vpaned->get_toplevel()->signal_map().connect(
1312  sigc::bind(
1313  sigc::mem_fun(*this, &PresetWindow::display_paned),
1314  true, paned_child_height));
1315  } else if (animated && rack_visible) {
1316  gx_gui::child_set_property(*main_vpaned, *preset_scrolledbox, "shrink", true);
1317  vpaned_pos = main_vpaned->get_allocation().get_height();
1318  int w, h;
1319  main_vpaned->get_handle_window()->get_size(w, h);
1320  vpaned_target = vpaned_pos - paned_child_height - h;
1321  main_vpaned->set_position(vpaned_pos);
1322  vpaned_step = paned_child_height / 5;
1323  preset_scrolledbox->show();
1324  animate_preset_show();
1325  Glib::signal_timeout().connect(sigc::mem_fun(*this, &PresetWindow::animate_preset_show), 20);
1326  } else {
1327  display_paned(false, paned_child_height);
1328  }
1329  } else {
1330  vpaned_target = main_vpaned->get_allocation().get_height();
1331  vpaned_pos = main_vpaned->get_position();
1332  if (animated && is_mapped && rack_visible) {
1333  vpaned_step = paned_child_height / 5;
1334  gx_gui::child_set_property(*main_vpaned, *preset_scrolledbox, "shrink", true);
1335  Glib::signal_timeout().connect(sigc::mem_fun(*this, &PresetWindow::animate_preset_hide), 20);
1336  } else {
1337  preset_scrolledbox->hide();
1338  }
1339  actions.organize->set_active(false);
1340  }
1341 }
iterator end()
Definition: gx_json.h:366
virtual gx_system::PresetFileGui * get_current_bank_file()=0
virtual void reorder_preset(gx_system::PresetFileGui &pf, const std::vector< Glib::ustring > &neworder)=0
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
virtual void bank_set_flag(gx_system::PresetFileGui *pf, int flag, bool v)=0
bool has_entry(const Glib::ustring &name)
Definition: gx_json.h:354
virtual bank_iterator bank_begin()=0
virtual std::string bank_get_filename(const Glib::ustring &bank)=0
Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > type_pb
virtual void pf_insert_before(gx_system::PresetFileGui &pf, const Glib::ustring &src, gx_system::PresetFileGui &pftgt, const Glib::ustring &pos, const Glib::ustring &name)=0
virtual void pf_insert_after(gx_system::PresetFileGui &pf, const Glib::ustring &src, gx_system::PresetFileGui &pftgt, const Glib::ustring &pos, const Glib::ustring &name)=0
virtual int bank_size()=0
virtual gx_system::PresetFileGui * get_bank_file(const Glib::ustring &bank) const =0
std::vector< Position >::iterator iterator
Definition: gx_json.h:321
int get_type() const
Definition: gx_json.h:361
virtual bool convert_preset(gx_system::PresetFileGui &pf)=0
Glib::RefPtr< Gtk::Action > save_changes
virtual gx_system::PresetFileGui * bank_insert_new(const Glib::ustring &newname)=0
virtual bool setting_is_preset()=0
std::string get_style_filepath(const std::string &basename) const
Definition: gx_system.h:461
bool is_mutable() const
Definition: gx_json.h:367
static MyTreeView * create_from_builder(BaseObjectType *cobject)
Glib::RefPtr< Gtk::ToggleAction > show_rack
virtual void erase_preset(gx_system::PresetFileGui &pf, const Glib::ustring &name)=0
virtual bool rename_bank(const Glib::ustring &oldname, Glib::ustring &newname)=0
const SettingsFileHeader & get_header()
Definition: gx_json.cpp:1117
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
Glib::RefPtr< Gtk::ActionGroup > group
virtual bool bank_remove(const Glib::ustring &bank)=0
virtual const Glib::ustring & get_current_bank()=0
Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > del_pb
void append(const Glib::ustring &name)
virtual bool bank_check_reparse()=0
virtual bool row_draggable_vfunc(const TreeModel::Path &path) const
Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > edit_pb
Glib::RefPtr< Gtk::Action > new_bank
virtual sigc::signal< void > & signal_selection_changed()=0
Glib::RefPtr< Gtk::ToggleAction > organize
std::string to_string(const T &t)
Definition: gx_system.h:523
void on_preset_select(bool v, bool animated, int preset_window_height)
PresetStore::PresetModelColumns col
virtual void load_preset(gx_system::PresetFileGui *pf, const Glib::ustring &name)=0
Glib::RefPtr< Gtk::AccelGroup > accels
Glib::RefPtr< Gtk::Action > online_preset_bank
void strip(Glib::ustring &s)
Definition: gx_system.cpp:970
Gtk::TreeModelColumn< Glib::ustring > name
PresetWindow(Glib::RefPtr< gx_gui::GxBuilder > bld, gx_engine::GxMachineBase &machine, const gx_system::CmdlineOptions &options, GxActions &actions, GtkSizeGroup *lc)
Gxw::BigKnob * wrap(GxBigKnob *object, bool take_copy)
Definition: bigknob.cc:44
void child_set_property(Gtk::Container &container, Gtk::Widget &child, const char *property_name, bool value)
Glib::RefPtr< Gtk::ToggleAction > presets
virtual bool rename_preset(gx_system::PresetFileGui &pf, const Glib::ustring &oldname, const Glib::ustring &newname)=0
Gtk::TreeModelColumn< int > tp
virtual void bank_reorder(const std::vector< Glib::ustring > &neworder)=0
const Glib::ustring & get_name(int n)
Definition: gx_json.cpp:1129
virtual const Glib::ustring & get_current_name()=0
int get_flags() const
Definition: gx_json.h:358
virtual void bank_drag_begin()=0
Gtk::TreeModelColumn< Glib::ustring > name
virtual void pf_append(gx_system::PresetFileGui &pf, const Glib::ustring &src, gx_system::PresetFileGui &pftgt, const Glib::ustring &name)=0
virtual void pf_save(gx_system::PresetFileGui &pf, const Glib::ustring &name)=0
virtual gx_system::PresetFileGui * bank_insert_uri(const Glib::ustring &uri, bool move)=0
virtual gx_system::PresetFileGui * bank_get_file(const Glib::ustring &bank) const =0
Gtk::TreeModelColumn< Glib::ustring > name
virtual bank_iterator bank_end()=0
Glib::ustring current_version_string() const
Definition: gx_json.h:248
Glib::ustring version_string() const
Definition: gx_json.h:247