mp3splt-gtk
splitpoints_window.c
Go to the documentation of this file.
1 /**********************************************************
2  *
3  * mp3splt-gtk -- utility based on mp3splt,
4  * for mp3/ogg splitting without decoding
5  *
6  * Copyright: (C) 2005-2012 Alexandru Munteanu
7  * Contact: m@ioalex.net
8  *
9  * http://mp3splt.sourceforge.net/
10  *
11  *********************************************************/
12 
13 /**********************************************************
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
28  * USA.
29  *
30  *********************************************************/
31 
32 /*!********************************************************
33  * \file
34  * The splitpoints tab
35  *
36  * this file is used for the Splitpoints tab
37  * (which in turn contains the splitpoints table)
38  **********************************************************/
39 
40 #include "splitpoints_window.h"
41 
43 static gboolean check_if_splitpoint_does_not_exists(gint minutes, gint seconds, gint hundr_secs,
44  gint current_split, ui_state *ui)
45 {
46  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
47 
48  GtkTreeIter iter;
49  if (!gtk_tree_model_get_iter_first(model, &iter))
50  {
51  return TRUE;
52  }
53 
54  gint tree_minutes;
55  gint tree_seconds;
56  gint tree_hundr_secs;
57 
58  while (TRUE)
59  {
60  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
61  COL_MINUTES, &tree_minutes,
62  COL_SECONDS, &tree_seconds,
63  COL_HUNDR_SECS, &tree_hundr_secs,
64  -1);
65 
66  GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
67  gint i = gtk_tree_path_get_indices (path)[0];
68 
69  if ((minutes == tree_minutes) &&
70  (seconds == tree_seconds) &&
71  (hundr_secs == tree_hundr_secs) &&
72  (i != current_split))
73  {
74  gtk_tree_path_free(path);
75  return FALSE;
76  }
77 
78  gtk_tree_path_free(path);
79 
80  if (!gtk_tree_model_iter_next(model, &iter))
81  {
82  break;
83  }
84  }
85 
86  return TRUE;
87 }
88 
94 static void update_add_button(ui_state *ui)
95 {
96  gui_status *status = ui->status;
97  if (check_if_splitpoint_does_not_exists(status->spin_mins, status->spin_secs, status->spin_hundr_secs,-1, ui))
98  {
99  gtk_widget_set_sensitive(GTK_WIDGET(ui->gui->add_button), TRUE);
100  }
101  else
102  {
103  gtk_widget_set_sensitive(GTK_WIDGET(ui->gui->add_button), FALSE);
104  }
105 }
106 
108 void update_minutes_from_spinner(GtkWidget *widget, ui_state *ui)
109 {
110  ui->status->spin_mins = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_minutes));
111  update_add_button(ui);
112 }
113 
115 void update_seconds_from_spinner(GtkWidget *widget, ui_state *ui)
116 {
117  ui->status->spin_secs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_seconds));
118  update_add_button(ui);
119 }
120 
122 void update_hundr_secs_from_spinner(GtkWidget *widget, ui_state *ui)
123 {
124  ui->status->spin_hundr_secs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_hundr_secs));
125  update_add_button(ui);
126 }
127 
129 static GtkTreeModel *create_model()
130 {
131  GtkListStore * model = gtk_list_store_new(NUM_COLUMNS,
132  G_TYPE_BOOLEAN,
133  G_TYPE_STRING,
134  G_TYPE_INT,
135  G_TYPE_INT,
136  G_TYPE_INT,
137  G_TYPE_STRING,
138  G_TYPE_STRING,
139  G_TYPE_STRING,
140  //tags
141  G_TYPE_STRING,
142  G_TYPE_STRING,
143  G_TYPE_STRING,
144  G_TYPE_STRING,
145  G_TYPE_INT,
146  G_TYPE_INT,
147  G_TYPE_STRING);
148 
149  return GTK_TREE_MODEL(model);
150 }
151 
153 static void recompute_length_column(ui_state *ui)
154 {
155  gint line_mins, line_secs, line_hundr;
156  gint line1_mins, line1_secs, line1_hundr;
157 
158  gchar new_length_string[30];
159 
160  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
161 
162  gint number = 0;
163  for (number = 0;number < ui->infos->splitnumber; number++)
164  {
165  GtkTreePath *path = gtk_tree_path_new_from_indices(number ,-1);
166  GtkTreeIter iter;
167  gtk_tree_model_get_iter(model, &iter, path);
168 
169  if (number != ui->infos->splitnumber-1)
170  {
171  GtkTreePath *path2 = gtk_tree_path_new_from_indices (number+1 ,-1);
172  GtkTreeIter iter2;
173  gtk_tree_model_get_iter(model, &iter2, path2);
174 
175  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
176  COL_MINUTES, &line_mins,
177  COL_SECONDS, &line_secs,
178  COL_HUNDR_SECS, &line_hundr,
179  -1);
180  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter2,
181  COL_MINUTES, &line1_mins,
182  COL_SECONDS, &line1_secs,
183  COL_HUNDR_SECS, &line1_hundr,
184  -1);
185 
186  gint result_secs = 0,result_hundr = 0;
187  gint result_mins = line1_mins - line_mins;
188  if ((result_secs = line1_secs - line_secs) < 0)
189  {
190  result_secs = 60 - line_secs + line1_secs;
191  result_mins--;
192  }
193 
194  if ((result_hundr = line1_hundr - line_hundr) < 0)
195  {
196  result_hundr = 100 - line_hundr + line1_hundr;
197  result_secs--;
198  if (result_secs < 0)
199  {
200  result_mins--;
201  result_secs = 0;
202  }
203  }
204 
205  g_snprintf(new_length_string, 30, "%d:%02d:%02d", result_mins, result_secs, result_hundr);
206 
207  gtk_tree_path_free(path2);
208  }
209  else
210  {
211  g_snprintf(new_length_string, 30, "%s","-");
212  }
213 
214  gtk_tree_path_free(path);
215 
216  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_NUMBER, new_length_string, -1);
217  }
218 }
219 
227 static gboolean check_if_description_exists(gchar *descr, gint number, ui_state *ui)
228 {
229  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
230 
231  GtkTreeIter iter;
232  if (!gtk_tree_model_get_iter_first(model, &iter))
233  {
234  return TRUE;
235  }
236 
237  gint count = 0;
238  while (TRUE)
239  {
240  gchar *description = NULL;
241  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
242  COL_DESCRIPTION, &description,
243  -1);
244 
245  if (description != NULL && strcmp(descr, description) == 0 && count != number)
246  {
247  g_free(description);
248  return FALSE;
249  }
250 
251  g_free(description);
252 
253  if (!gtk_tree_model_iter_next(model, &iter))
254  break;
255 
256  count++;
257  }
258 
259  return TRUE;
260 }
261 
264 {
265  gint splitpoint_selected = -1;
266 
267  GtkTreeModel *model = gtk_tree_view_get_model(gui->tree_view);
268  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
269 
270  GList *selected_list =
271  gtk_tree_selection_get_selected_rows(GTK_TREE_SELECTION(selection), &model);
272 
273  if (g_list_length(selected_list) > 0)
274  {
275  GList *current_element = g_list_first(selected_list);
276  GtkTreePath *path = current_element->data;
277  splitpoint_selected = gtk_tree_path_get_indices (path)[0];
278 
279  g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
280  g_list_free(selected_list);
281  }
282 
283  return splitpoint_selected;
284 }
285 
287 static void row_selection_event(GtkTreeSelection *selection, ui_state *ui)
288 {
289  gtk_widget_set_sensitive(ui->gui->remove_row_button, TRUE);
290 }
291 
302 static void update_current_description(gchar *descr, gint number, ui_state *ui)
303 {
304  gint ll = 0;
305 
306  gchar *current_description = ui->status->current_description;
307 
308  g_snprintf(current_description, 255, "%s", descr);
309 
310  while (ll < ui->infos->splitnumber)
311  {
312  if (check_if_description_exists(current_description, number, ui))
313  {
314  ll++;
315  continue;
316  }
317 
318  //we cut the part _* from the string and put it back
319  gchar *tmp = NULL;
320  gchar *t = current_description;
321  while ((t = strstr(t, _("_part"))) != NULL)
322  {
323  tmp = t++;
324  }
325 
326  if (tmp != NULL)
327  {
328  *tmp = '\0';
329  }
330 
331  gchar *temp = g_strdup(current_description);
332  g_snprintf(current_description, 255, _("%s_part%d"), temp, ll + 2);
333  g_free(temp);
334 
335  ll++;
336  }
337 }
338 
343 void get_hundr_secs_mins_time(gint time_pos, gint *time_hundr,
344  gint *time_secs,gint *time_mins)
345 {
346  *time_hundr = time_pos % 100;
347  time_pos = time_pos / 100;
348  *time_secs = time_pos % 60;
349  time_pos = time_pos / 60;
350  *time_mins = time_pos;
351 }
352 
354 void select_splitpoint(gint index, gui_state *gui)
355 {
356  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
357  GtkTreeModel *model = gtk_tree_view_get_model(gui->tree_view);
358  GtkTreePath *path = gtk_tree_path_new_from_indices(index ,-1);
359 
360  GtkTreeIter iter;
361  gtk_tree_model_get_iter(model, &iter, path);
362  gtk_tree_selection_unselect_all(selection);
363  gtk_tree_selection_select_iter(selection, &iter);
364 
365  gtk_tree_path_free(path);
366 
368 }
369 
370 static void order_all_splitpoints_from_table(const char *current_description_base,
371  GtkTreeModel *model, ui_state *ui)
372 {
373  GtkTreeIter iter;
374  if (!gtk_tree_model_get_iter_first(model, &iter))
375  {
376  return;
377  }
378 
379  int description_base_length = strlen(current_description_base);
380 
381  gint i = 0;
382  gint description_counter = 0;
383  while (i < ui->infos->splitnumber)
384  {
385  gchar *description = NULL;
386  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
387  COL_DESCRIPTION, &description,
388  -1);
389 
390  int length = strlen(description);
391  if (length >= description_base_length)
392  {
393  if (strncmp(description, current_description_base, description_base_length) == 0)
394  {
395  GString *new_description = g_string_new("");
396  g_string_append_printf(new_description, "%s_part%d", current_description_base,
397  i + 1);
398  gchar *new_desc = g_string_free(new_description, FALSE);
399 
400  gtk_list_store_set(GTK_LIST_STORE(model),
401  &iter,
402  COL_DESCRIPTION, new_desc,
403  -1);
404 
405  g_free(new_desc);
406  description_counter++;
407  }
408  }
409 
410  g_free(description);
411 
412  gtk_tree_model_iter_next(model, &iter);
413  i++;
414  }
415 }
416 
421 void remove_splitpoint(gint index, gint stop_preview, ui_state *ui)
422 {
423  g_array_remove_index(ui->splitpoints, index);
424 
425  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
426  GtkTreePath *path = gtk_tree_path_new_from_indices (index ,-1);
427 
428  GtkTreeIter iter;
429  gtk_tree_model_get_iter(model, &iter, path);
430 
431  //cancel quick preview if necessary
432  if (((index == ui->status->preview_start_splitpoint) && stop_preview) ||
433  ((index == get_quick_preview_end_splitpoint_safe(ui)) &&
434  (get_quick_preview_end_splitpoint_safe(ui) == (ui->infos->splitnumber-1)) && stop_preview))
435  {
437  }
438 
439  //if we remove a point at the left of the play preview, move the indexes
440  if (index < ui->status->preview_start_splitpoint)
441  {
442  ui->status->preview_start_splitpoint--;
443  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
444  }
445 
446  gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
447  gtk_tree_path_free(path);
448 
449  ui->infos->splitnumber--;
450 
451  if (get_first_splitpoint_selected(ui->gui) == -1)
452  {
453  gtk_widget_set_sensitive(ui->gui->remove_row_button, FALSE);
454  }
455 
456  if (ui->infos->splitnumber == 0)
457  {
458  gtk_widget_set_sensitive(ui->gui->remove_all_button, FALSE);
459  }
460 
461  if (stop_preview)
462  {
463  order_all_splitpoints_from_table(ui->status->current_description, model, ui);
464  }
465 
466  recompute_length_column(ui);
467  remove_status_message(ui->gui);
468  update_add_button(ui);
470  refresh_drawing_area(ui->gui);
471 
472  export_cue_file_in_configuration_directory(ui);
473 }
474 
481 static void add_splitpoint(Split_point my_split_point, gint old_index, ui_state *ui,
482  gint reorder_names, gchar *old_description)
483 {
484  gchar *current_description_base = g_strdup(ui->status->current_description);
485 
486  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
487 
488  if (check_if_splitpoint_does_not_exists(my_split_point.mins,
489  my_split_point.secs, my_split_point.hundr_secs,-1, ui))
490  {
491  gint k = 0;
492 
493  update_current_description(current_description_base, -1, ui);
494 
495  GtkTreeIter iter;
496  if (gtk_tree_model_get_iter_first(model, &iter))
497  {
498  while (k < ui->infos->splitnumber)
499  {
500  gint tree_minutes;
501  gint tree_seconds;
502  gint tree_hundr_secs;
503  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
504  COL_MINUTES, &tree_minutes,
505  COL_SECONDS, &tree_seconds,
506  COL_HUNDR_SECS, &tree_hundr_secs,
507  -1);
508 
509  if (my_split_point.mins < tree_minutes)
510  {
511  break;
512  }
513  else if (my_split_point.mins == tree_minutes)
514  {
515  if (my_split_point.secs < tree_seconds)
516  {
517  break;
518  }
519  else if (my_split_point.secs == tree_seconds)
520  {
521  if (my_split_point.hundr_secs < tree_hundr_secs)
522  {
523  break;
524  }
525  }
526  }
527 
528  gtk_tree_model_iter_next(model, &iter);
529  k++;
530  }
531 
532  gtk_list_store_insert(GTK_LIST_STORE(model), &iter,k--);
533  g_array_insert_val(ui->splitpoints, k+1, my_split_point);
534  }
535  else
536  {
537  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
538  g_array_append_val(ui->splitpoints, my_split_point);
539  }
540 
541  ui->infos->splitnumber++;
542 
543  //we keep the selection on the previous splipoint
544  if ((ui->status->first_splitpoint_selected == old_index) &&
545  (old_index != -1))
546  {
547  GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
548  gtk_tree_view_set_cursor(ui->gui->tree_view, path, NULL, FALSE);
549  gtk_tree_path_free(path);
550  }
551 
552  if (ui->status->quick_preview)
553  {
554  //if we move the current start preview splitpoint
555  //at the right of the current time, we cancel preview
556  if (old_index == ui->status->preview_start_splitpoint)
557  {
558  if (ui->infos->current_time < get_splitpoint_time(ui->status->preview_start_splitpoint, ui))
559  {
560  cancel_quick_preview(ui->status);
561  }
562  }
563  }
564 
565  //we manage the play preview here
566  if (old_index != -1)
567  {
568  //if we have a split preview on going
569  //if we move the point from the left to the right of the
570  //the start preview splitpoint
571  if ((old_index < ui->status->preview_start_splitpoint))
572  {
573  if ((k+1) >= ui->status->preview_start_splitpoint)
574  {
575  ui->status->preview_start_splitpoint--;
576  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
577  }
578  }
579  else
580  {
581  //if we move from the right of the split preview to his left
582  if ((old_index > ui->status->preview_start_splitpoint))
583  {
584  if ((k+1) <= ui->status->preview_start_splitpoint)
585  {
586  ui->status->preview_start_splitpoint++;
587  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
588  }
589  }
590  else
591  {
592  //if we move the start splitpoint on the right of the end splitpoint
593  if (old_index == ui->status->preview_start_splitpoint)
594  {
595  if ((k+1) > ui->status->preview_start_splitpoint)
596  {
597  ui->status->preview_start_splitpoint += (k+1) - ui->status->preview_start_splitpoint;
598  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
599  }
600  else
601  {
602  //if we move the start splitpoint at the left
603  if ((k+1) < ui->status->preview_start_splitpoint)
604  {
605  ui->status->preview_start_splitpoint -= ui->status->preview_start_splitpoint - (k + 1);
606  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
607  }
608  }
609  }
610  }
611  }
612 
613  if (ui->status->preview_start_splitpoint == (ui->infos->splitnumber-1))
614  {
616  }
617  }
618  else
619  {
620  //if we add a splitpoint at the left of the quick
621  //preview start, add 1
622  if ((k+1) <= ui->status->preview_start_splitpoint)
623  {
624  ui->status->preview_start_splitpoint++;
625  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
626  }
627  }
628 
629  //put values in the line
630  //sets text in the minute, second and milisecond column
631  gtk_list_store_set(GTK_LIST_STORE(model),
632  &iter,
633  COL_CHECK, my_split_point.checked,
634  COL_DESCRIPTION, ui->status->current_description,
635  COL_MINUTES, my_split_point.mins,
636  COL_SECONDS, my_split_point.secs,
637  COL_HUNDR_SECS, my_split_point.hundr_secs,
638  -1);
639 
640  gtk_widget_set_sensitive(ui->gui->remove_all_button, TRUE);
641 
642  recompute_length_column(ui);
643  remove_status_message(ui->gui);
644  }
645  else
646  {
647  put_status_message(_(" error: you already have the splitpoint in table"), ui);
648  }
649 
650  if (reorder_names)
651  {
652  if (old_description)
653  {
654  order_all_splitpoints_from_table(old_description, model, ui);
655  }
656  else
657  {
658  order_all_splitpoints_from_table(current_description_base, model, ui);
659  }
660  }
661 
662  if (old_description) { g_free(old_description); }
663  if (current_description_base) { g_free(current_description_base); }
664 
665  if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
666  {
667  copy_filename_to_current_description(get_input_filename(ui->gui), ui);
668  }
669  else
670  {
671  g_snprintf(ui->status->current_description, 255, "%s", _("description here"));
672  }
673 
674  update_add_button(ui);
675  refresh_drawing_area(ui->gui);
677 
678  export_cue_file_in_configuration_directory(ui);
679 }
680 
690 void update_splitpoint(gint index, Split_point new_point, ui_state *ui)
691 {
692  int splitpoint_does_not_exists =
693  check_if_splitpoint_does_not_exists(new_point.mins, new_point.secs, new_point.hundr_secs,-1, ui);
694 
695  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
696 
697  if (splitpoint_does_not_exists ||
698  (old_point.checked != new_point.checked))
699  {
700  ui->status->lock_cue_export = SPLT_TRUE;
701 
702  ui->status->first_splitpoint_selected = get_first_splitpoint_selected(ui->gui);
703 
704  gchar *old_description = g_strdup(ui->status->current_description);
705 
706  gchar *description = get_splitpoint_name(index, ui);
707  g_snprintf(ui->status->current_description, 255, "%s", description);
708  g_free(description);
709 
710  //backup tags
711  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
712  GtkTreePath *path = gtk_tree_path_new_from_indices(index ,-1);
713  GtkTreeIter iter;
714  gtk_tree_model_get_iter(model, &iter, path);
715 
716  gint year = 0, track = 0;
717  gchar *title = NULL, *artist = NULL, *album = NULL, *genre = NULL, *comment = NULL;
718  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
719  COL_TITLE, &title,
720  COL_ARTIST, &artist,
721  COL_ALBUM, &album,
722  COL_GENRE, &genre,
723  COL_COMMENT, &comment,
724  COL_YEAR, &year,
725  COL_TRACK, &track,
726  -1);
727 
728  remove_splitpoint(index, FALSE, ui);
729  add_splitpoint(new_point, index, ui, TRUE, old_description);
730 
731  //restore tags
732  gtk_tree_model_get_iter(model, &iter, path);
733  gtk_tree_path_free(path);
734 
735  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_TITLE, title, -1);
736  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_ARTIST, artist, -1);
737  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_ALBUM, album, -1);
738  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_GENRE, genre, -1);
739  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_COMMENT, comment, -1);
740  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_YEAR, year, -1);
741  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_TRACK, track, -1);
742  free(title); free(artist); free(album); free(genre); free(comment);
743 
744  ui->status->lock_cue_export = SPLT_FALSE;
745 
746  export_cue_file_in_configuration_directory(ui);
747  }
748  else
749  {
750  //don't put error if we move the same splitpoint
751  //on the same place
752  if ((new_point.mins == old_point.mins) &&
753  (new_point.secs == old_point.secs) &&
754  (new_point.hundr_secs == old_point.hundr_secs))
755  {
756  }
757  else
758  {
759  put_status_message(_(" error: you already have the splitpoint in table"), ui);
760  }
761  }
762 }
763 
768 void update_splitpoint_from_time(gint index, gdouble time, ui_state *ui)
769 {
770  Split_point new_point;
771  get_hundr_secs_mins_time((gint)time, &new_point.hundr_secs, &new_point.secs, &new_point.mins);
772  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
773  new_point.checked = old_point.checked;
774 
775  update_splitpoint(index, new_point, ui);
776 }
777 
783 void update_splitpoint_check(gint index, ui_state *ui)
784 {
785  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
786  old_point.checked ^= 1;
787  update_splitpoint(index, old_point, ui);
788 }
789 
790 void clear_current_description(ui_state *ui)
791 {
792  update_current_description(_("description here"), -1, ui);
793 }
794 
795 void copy_filename_to_current_description(const gchar *fname, ui_state *ui)
796 {
797  if (strcmp(fname, "") == 0)
798  {
799  clear_current_description(ui);
800  }
801 
802  gchar *temp = g_strdup(g_path_get_basename(fname));
803  gchar *tmp = strrchr(temp,'.');
804  if (tmp != NULL) { *tmp = '\0'; }
805 
806  g_snprintf(ui->status->current_description, 255, "%s", temp);
807  g_free(temp);
808 }
809 
811 static void cell_edited_event(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, ui_state *ui)
812 {
813  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
814  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
815 
816  gint col = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "col"));
817 
818  GtkTreeIter iter;
819  gtk_tree_model_get_iter(model, &iter, path);
820  gint i = gtk_tree_path_get_indices (path)[0];
821  Split_point old_point = g_array_index(ui->splitpoints, Split_point, i);
822 
823  Split_point new_point;
824  new_point.checked = old_point.checked;
825 
826  switch (col)
827  {
828  case COL_DESCRIPTION:
829  update_current_description(new_text, i, ui);
830 
831  //put the new content in the list
832  gtk_list_store_set(GTK_LIST_STORE(model), &iter,
833  col, ui->status->current_description,
834  -1);
835 
836  if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
837  {
838  copy_filename_to_current_description(get_input_filename(ui->gui), ui);
839  }
840  else
841  {
842  g_snprintf(ui->status->current_description, 255, "%s", _("description here"));
843  }
844  break;
845  //seconds column
846  case COL_SECONDS:
847  new_point.mins = old_point.mins;
848  new_point.secs = atoi(new_text);
849  new_point.hundr_secs = old_point.hundr_secs;
850 
851  if (new_point.secs < 0)
852  {
853  new_point.secs = 0;
854  }
855  if (new_point.secs > 59)
856  {
857  new_point.secs = 59;
858  }
859 
860  update_splitpoint(i, new_point, ui);
861  break;
862  //minutes column
863  case COL_MINUTES:
864  new_point.mins = atoi(new_text);
865  new_point.secs = old_point.secs;
866  new_point.hundr_secs = old_point.hundr_secs;
867 
868  if (new_point.mins < 0)
869  {
870  new_point.mins = 0;
871  }
872  if (new_point.mins > INT_MAX/6000)
873  {
874  new_point.mins = INT_MAX/6000;
875  }
876 
877  update_splitpoint(i, new_point, ui);
878  break;
879  //hundreth column
880  case COL_HUNDR_SECS:
881  new_point.mins = old_point.mins;
882  new_point.secs = old_point.secs;
883  new_point.hundr_secs = atoi(new_text);
884 
885  if (new_point.hundr_secs < 0)
886  {
887  new_point.hundr_secs = 0;
888  }
889  if (new_point.hundr_secs > 99)
890  {
891  new_point.hundr_secs = 99;
892  }
893 
894  update_splitpoint(i, new_point, ui);
895  break;
896  case COL_YEAR:
897  case COL_TRACK:
898  ;
899  gint value = (gint) atoi(new_text);
900  if (value < 0) { value = 0; }
901  gtk_list_store_set(GTK_LIST_STORE(model), &iter, col, value, -1);
902  break;
903  default:
904  gtk_list_store_set(GTK_LIST_STORE(model), &iter, col, new_text, -1);
905  break;
906  }
907 
908  gtk_tree_path_free(path);
909 
910  export_cue_file_in_configuration_directory(ui);
911 }
912 
913 void add_splitpoint_from_player(GtkWidget *widget, ui_state *ui)
914 {
915  if (!ui->status->timer_active)
916  {
917  return;
918  }
919 
920  Split_point my_split_point;
921  my_split_point.mins = ui->infos->player_minutes;
922  my_split_point.secs = ui->infos->player_seconds;
923  my_split_point.hundr_secs = ui->infos->player_hundr_secs;
924  my_split_point.checked = TRUE;
925 
926  add_splitpoint(my_split_point, -1, ui, TRUE, NULL);
927 }
928 
930 void add_row(gboolean checked, ui_state *ui)
931 {
932  gui_status *status = ui->status;
933 
934  Split_point my_split_point;
935  my_split_point.mins = status->spin_mins;
936  my_split_point.secs = status->spin_secs;
937  my_split_point.hundr_secs = status->spin_hundr_secs;
938  my_split_point.checked = checked;
939 
940  add_splitpoint(my_split_point, -1, ui, FALSE, NULL);
941 }
942 
943 static void add_row_clicked(GtkWidget *button, ui_state *ui)
944 {
945  gui_status *status = ui->status;
946 
947  Split_point my_split_point;
948  my_split_point.mins = status->spin_mins;
949  my_split_point.secs = status->spin_secs;
950  my_split_point.hundr_secs = status->spin_hundr_secs;
951  my_split_point.checked = TRUE;
952 
953  add_splitpoint(my_split_point, -1, ui, TRUE, NULL);
954 }
955 
956 static gboolean detect_silence_and_set_splitpoints_end(ui_with_err *ui_err)
957 {
958  gint err = ui_err->err;
959  ui_state *ui = ui_err->ui;
960 
962  mp3splt_set_split_filename_function(ui->mp3splt_state, lmanager_put_split_filename, ui);
963 
964  if (err >= 0)
965  {
967  }
968 
970 
971  gtk_widget_set_sensitive(ui->gui->cancel_button, FALSE);
972  gtk_widget_set_sensitive(ui->gui->scan_silence_button, TRUE);
973  gtk_widget_set_sensitive(ui->gui->scan_silence_button_player, TRUE);
974  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button, TRUE);
975  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button_player, TRUE);
976 
977  set_is_splitting_safe(FALSE, ui);
978 
979  set_process_in_progress_and_wait_safe(FALSE, ui);
980 
981  g_free(ui_err);
982 
983  return FALSE;
984 }
985 
986 static void set_should_trim_safe(gboolean value, ui_state *ui)
987 {
988  lock_mutex(&ui->variables_mutex);
989  ui->status->should_trim = value;
990  unlock_mutex(&ui->variables_mutex);
991 }
992 
993 static gint get_should_trim_safe(ui_state *ui)
994 {
995  lock_mutex(&ui->variables_mutex);
996  gint should_trim = ui->status->should_trim;
997  unlock_mutex(&ui->variables_mutex);
998  return should_trim;
999 }
1000 
1002 static gpointer detect_silence_and_set_splitpoints(ui_state *ui)
1003 {
1004  set_process_in_progress_and_wait_safe(TRUE, ui);
1005 
1006  set_is_splitting_safe(TRUE, ui);
1007 
1008  gint err = SPLT_OK;
1009 
1010  enter_threads();
1011 
1012  gtk_widget_set_sensitive(ui->gui->scan_silence_button, FALSE);
1013  gtk_widget_set_sensitive(ui->gui->scan_silence_button_player, FALSE);
1014  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button, FALSE);
1015  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button_player, FALSE);
1016  gtk_widget_set_sensitive(ui->gui->cancel_button, TRUE);
1017  gchar *format = strdup(gtk_entry_get_text(GTK_ENTRY(ui->gui->output_entry)));
1018 
1019  lock_mutex(&ui->variables_mutex);
1020  mp3splt_set_filename_to_split(ui->mp3splt_state, get_input_filename(ui->gui));
1021  unlock_mutex(&ui->variables_mutex);
1022 
1023  gint checked_output_radio_box = get_checked_output_radio_box(ui);
1024 
1025  exit_threads();
1026 
1027  err = mp3splt_erase_all_splitpoints(ui->mp3splt_state);
1028 
1029  if (checked_output_radio_box == 0)
1030  {
1031  err = mp3splt_set_oformat(ui->mp3splt_state, format);
1032  }
1033 
1034  if (format)
1035  {
1036  free(format);
1037  format = NULL;
1038  }
1039 
1041  mp3splt_set_split_filename_function(ui->mp3splt_state, NULL, ui);
1043 
1044  print_status_bar_confirmation_in_idle(err, ui);
1045 
1046  err = SPLT_OK;
1047  int old_split_mode = mp3splt_get_int_option(ui->mp3splt_state, SPLT_OPT_SPLIT_MODE, &err);
1048  int old_tags_option = mp3splt_get_int_option(ui->mp3splt_state, SPLT_OPT_TAGS, &err);
1049 
1050  if (get_should_trim_safe(ui))
1051  {
1052  err = mp3splt_set_trim_silence_points(ui->mp3splt_state);
1053  }
1054  else
1055  {
1056  mp3splt_set_silence_points(ui->mp3splt_state, &err);
1057  }
1058 
1059  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_TAGS, old_tags_option);
1060  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_SPLIT_MODE, old_split_mode);
1061 
1062  ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
1063  ui_err->err = err;
1064  ui_err->ui = ui;
1065 
1066  gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE,
1067  (GSourceFunc)detect_silence_and_set_splitpoints_end, ui_err, NULL);
1068 
1069  return NULL;
1070 }
1071 
1072 static void detect_silence_and_set_splitpoints_action(ui_state *ui)
1073 {
1074  create_thread((GThreadFunc)detect_silence_and_set_splitpoints, ui);
1075 }
1076 
1078 static void detect_silence_and_add_splitpoints_start_thread(ui_state *ui)
1079 {
1080  set_should_trim_safe(FALSE, ui);
1081  detect_silence_and_set_splitpoints_action(ui);
1082 }
1083 
1084 static void detect_silence_and_add_trim_splitpoints_start_thread(ui_state *ui)
1085 {
1086  set_should_trim_safe(TRUE, ui);
1087  detect_silence_and_set_splitpoints_action(ui);
1088 }
1089 
1091 static void update_silence_parameters(GtkWidget *widget, ui_state *ui)
1092 {
1093  ui_infos *infos = ui->infos;
1094  gui_state *gui = ui->gui;
1095 
1096  infos->silence_threshold_value =
1097  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_threshold));
1098  if (gui->spinner_silence_offset != NULL)
1099  {
1100  infos->silence_offset_value =
1101  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_offset));
1102  }
1103  if (gui->spinner_silence_number_tracks != NULL)
1104  {
1105  infos->silence_number_of_tracks =
1106  gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gui->spinner_silence_number_tracks));
1107  }
1108  if (gui->spinner_silence_minimum != NULL)
1109  {
1110  infos->silence_minimum_length =
1111  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_minimum));
1112  }
1113  if (gui->spinner_silence_minimum_track != NULL)
1114  {
1115  infos->silence_minimum_track_length =
1116  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_minimum_track));
1117  }
1118  if (gui->silence_remove_silence != NULL)
1119  {
1120  infos->silence_remove_silence_between_tracks =
1121  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->silence_remove_silence));
1122  }
1123 }
1124 
1126 static void silence_remove_silence_checked(GtkToggleButton *button, ui_state *ui)
1127 {
1128  update_silence_parameters(GTK_WIDGET(button), ui);
1129 }
1130 
1131 void create_trim_silence_window(GtkWidget *button, ui_state *ui)
1132 {
1133  GtkWidget *silence_detection_window =
1134  gtk_dialog_new_with_buttons(_("Set trim splitpoints using silence detection"),
1135  GTK_WINDOW(ui->gui->window),
1136  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1137  GTK_STOCK_OK,
1138  GTK_RESPONSE_YES,
1139  GTK_STOCK_CANCEL,
1140  GTK_RESPONSE_CANCEL,
1141  NULL);
1142 
1143  gtk_widget_set_size_request(silence_detection_window, 300, 90);
1144 
1145  GtkWidget *general_inside_vbox = wh_vbox_new();
1146 
1147  GtkWidget *horiz_fake = wh_hbox_new();
1148  gtk_box_pack_start(GTK_BOX(general_inside_vbox), horiz_fake, FALSE, FALSE, 10);
1149 
1150  //vertical parameter box
1151  GtkWidget *param_vbox = wh_vbox_new();
1152  gtk_box_pack_start(GTK_BOX(horiz_fake), param_vbox, FALSE, FALSE, 25);
1153 
1154  //horizontal box fake for threshold level
1155  horiz_fake = wh_hbox_new();
1156  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1157 
1158  //threshold level
1159  GtkWidget *label = gtk_label_new(_("Threshold level (dB):"));
1160  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1161 
1162  //adjustement for the threshold spinner
1163  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -96.0, 0.0, 0.5, 10.0, 0.0);
1164  GtkWidget *spinner_silence_threshold = gtk_spin_button_new(adj, 0.5, 2);
1165  ui->gui->spinner_silence_threshold = spinner_silence_threshold;
1166  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_threshold, FALSE, FALSE, 6);
1167  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_threshold), ui->infos->silence_threshold_value);
1168  g_signal_connect(G_OBJECT(spinner_silence_threshold), "value_changed",
1169  G_CALLBACK(update_silence_parameters), ui);
1170 
1171  gtk_widget_show_all(general_inside_vbox);
1172  gtk_container_add(GTK_CONTAINER(
1173  gtk_dialog_get_content_area(GTK_DIALOG(silence_detection_window))), general_inside_vbox);
1174 
1175  gint result = gtk_dialog_run(GTK_DIALOG(silence_detection_window));
1176 
1177  gtk_widget_destroy(silence_detection_window);
1178 
1179  if (result == GTK_RESPONSE_YES)
1180  {
1181  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_THRESHOLD, ui->infos->silence_threshold_value);
1182  detect_silence_and_add_trim_splitpoints_start_thread(ui);
1183  }
1184 }
1185 
1188 {
1189  ui_infos *infos = ui->infos;
1190  gui_state *gui = ui->gui;
1191 
1192  GtkWidget *silence_detection_window =
1193  gtk_dialog_new_with_buttons(_("Set splitpoints from silence detection"),
1194  GTK_WINDOW(gui->window),
1195  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1196  GTK_STOCK_OK,
1197  GTK_RESPONSE_YES,
1198  GTK_STOCK_CANCEL,
1199  GTK_RESPONSE_CANCEL,
1200  NULL);
1201 
1202  GtkWidget *general_inside_vbox = wh_vbox_new();
1203  GtkWidget *horiz_fake = wh_hbox_new();
1204  gtk_box_pack_start(GTK_BOX(general_inside_vbox), horiz_fake, FALSE, FALSE, 10);
1205 
1206  //vertical parameter box
1207  GtkWidget *param_vbox = wh_vbox_new();
1208  gtk_box_pack_start(GTK_BOX(horiz_fake), param_vbox, FALSE, FALSE, 25);
1209 
1210  //horizontal box fake for threshold level
1211  horiz_fake = wh_hbox_new();
1212  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1213 
1214  //threshold level
1215  GtkWidget *label = gtk_label_new(_("Threshold level (dB):"));
1216  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1217 
1218  //adjustement for the threshold spinner
1219  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -96.0, 0.0, 0.5, 10.0, 0.0);
1220  GtkWidget *spinner_silence_threshold = gtk_spin_button_new(adj, 0.5, 2);
1221  gui->spinner_silence_threshold = spinner_silence_threshold;
1222  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_threshold, FALSE, FALSE, 6);
1223 
1224  //horizontal box fake for the offset level
1225  horiz_fake = wh_hbox_new();
1226  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1227 
1228  //offset level
1229  label = gtk_label_new(_("Cutpoint offset (0 is the begin of silence,"
1230  "and 1 the end):"));
1231  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1232 
1233  //adjustement for the offset spinner
1234  adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -2, 2, 0.05, 10.0, 0.0);
1235  GtkWidget *spinner_silence_offset = gtk_spin_button_new(adj, 0.05, 2);
1236  gui->spinner_silence_offset = spinner_silence_offset;
1237  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_offset, FALSE, FALSE, 6);
1238 
1239  //number of tracks
1240  horiz_fake = wh_hbox_new();
1241  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1242 
1243  label = gtk_label_new(_("Number of tracks (0 means all tracks):"));
1244  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1245 
1246  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 1, 10.0, 0.0);
1247  GtkWidget *spinner_silence_number_tracks = gtk_spin_button_new(adj, 1, 0);
1248  gui->spinner_silence_number_tracks = spinner_silence_number_tracks;
1249  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_number_tracks, FALSE, FALSE, 6);
1250 
1251  //minimum length
1252  horiz_fake = wh_hbox_new();
1253  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1254 
1255  label = gtk_label_new(_("Minimum silence length (seconds):"));
1256  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1257 
1258  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 0.5, 10.0, 0.0);
1259  GtkWidget *spinner_silence_minimum = gtk_spin_button_new(adj, 1, 2);
1260  gui->spinner_silence_minimum = spinner_silence_minimum;
1261  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_minimum, FALSE, FALSE, 6);
1262 
1263  //the minimum track length parameter
1264  horiz_fake = wh_hbox_new();
1265  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1266 
1267  label = gtk_label_new(_("Minimum track length (seconds):"));
1268  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1269 
1270  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 0.5, 10.0, 0.0);
1271  GtkWidget *spinner_silence_minimum_track = gtk_spin_button_new(adj, 1, 2);
1272  gui->spinner_silence_minimum_track = spinner_silence_minimum_track;
1273  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_minimum_track, FALSE, FALSE, 6);
1274 
1275  //remove silence (rm): allows you to remove the silence between
1276  //tracks
1277  GtkWidget *silence_remove_silence = gtk_check_button_new_with_mnemonic(_("_Remove silence between tracks"));
1278  gui->silence_remove_silence = silence_remove_silence;
1279  gtk_box_pack_start(GTK_BOX(param_vbox), silence_remove_silence, FALSE, FALSE, 0);
1280 
1281  //we set the default parameters for the silence split
1282  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_threshold),
1283  infos->silence_threshold_value);
1284  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_offset),
1285  infos->silence_offset_value);
1286  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_number_tracks),
1287  infos->silence_number_of_tracks);
1288  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_minimum),
1289  infos->silence_minimum_length);
1290  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_minimum_track),
1291  infos->silence_minimum_track_length);
1292  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(silence_remove_silence),
1293  infos->silence_remove_silence_between_tracks);
1294 
1295  //add actions when changing the values
1296  g_signal_connect(G_OBJECT(spinner_silence_threshold), "value_changed",
1297  G_CALLBACK(update_silence_parameters), ui);
1298  g_signal_connect(G_OBJECT(spinner_silence_offset), "value_changed",
1299  G_CALLBACK(update_silence_parameters), ui);
1300  g_signal_connect(G_OBJECT(spinner_silence_number_tracks), "value_changed",
1301  G_CALLBACK(update_silence_parameters), ui);
1302  g_signal_connect(G_OBJECT(spinner_silence_minimum), "value_changed",
1303  G_CALLBACK(update_silence_parameters), ui);
1304  g_signal_connect(G_OBJECT(spinner_silence_minimum_track), "value_changed",
1305  G_CALLBACK(update_silence_parameters), ui);
1306  g_signal_connect(G_OBJECT(silence_remove_silence), "toggled",
1307  G_CALLBACK(silence_remove_silence_checked), ui);
1308 
1309  gtk_widget_show_all(general_inside_vbox);
1310  gtk_container_add(GTK_CONTAINER(
1311  gtk_dialog_get_content_area(GTK_DIALOG(silence_detection_window))),
1312  general_inside_vbox);
1313 
1314  gint result = gtk_dialog_run(GTK_DIALOG(silence_detection_window));
1315 
1316  gtk_widget_destroy(silence_detection_window);
1317 
1318  if (result == GTK_RESPONSE_YES)
1319  {
1321  infos->silence_threshold_value);
1322  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_OFFSET,
1323  infos->silence_offset_value);
1325  infos->silence_number_of_tracks);
1327  infos->silence_minimum_length);
1329  infos->silence_minimum_track_length);
1331  infos->silence_remove_silence_between_tracks);
1332 
1333  detect_silence_and_add_splitpoints_start_thread(ui);
1334  }
1335 }
1336 
1338 static void remove_row(GtkWidget *widget, ui_state *ui)
1339 {
1340  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1341  GtkTreeSelection *selection = gtk_tree_view_get_selection(ui->gui->tree_view);
1342 
1343  GList *selected_list = gtk_tree_selection_get_selected_rows(selection, &model);
1344 
1345  while ((g_list_length(selected_list) > 0) && (ui->infos->splitnumber > 0))
1346  {
1347  GList *current_element = g_list_last(selected_list);
1348  GtkTreePath *path = current_element->data;
1349  gint i = gtk_tree_path_get_indices (path)[0];
1350 
1351  remove_splitpoint(i, TRUE, ui);
1352 
1353  selected_list = g_list_remove(selected_list, path);
1354 
1355  gtk_tree_path_free(path);
1356  }
1357 
1358  g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
1359  g_list_free(selected_list);
1360 }
1361 
1363 void remove_all_rows(GtkWidget *widget, ui_state *ui)
1364 {
1365  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1366 
1367  while (ui->infos->splitnumber > 0)
1368  {
1369  GtkTreeIter iter;
1370  gtk_tree_model_get_iter_first(model, &iter);
1371  gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1372  g_array_remove_index(ui->splitpoints, (ui->infos->splitnumber-1));
1373  ui->infos->splitnumber--;
1374  }
1375 
1376  gtk_widget_set_sensitive(ui->gui->remove_all_button, FALSE);
1377  gtk_widget_set_sensitive(ui->gui->remove_row_button, FALSE);
1378 
1379  remove_status_message(ui->gui);
1381  update_add_button(ui);
1382  refresh_drawing_area(ui->gui);
1384 
1385  export_cue_file_in_configuration_directory(ui);
1386 }
1387 
1389 static GtkWidget *create_init_spinner(GtkWidget *bottomhbox1, gint min, gint max,
1390  gchar *label_text, gint type, ui_state *ui)
1391 {
1392  GtkWidget *spinner_box = wh_vbox_new();
1393  GtkWidget *label = gtk_label_new(label_text);
1394  gtk_box_pack_start(GTK_BOX(spinner_box), label, TRUE, FALSE, 0);
1395 
1396  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, min, max, 1.0, 10.0, 0.0);
1397  GtkWidget *spinner = gtk_spin_button_new(adj, 0, 0);
1398  gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner), TRUE);
1399 
1400  if (type == 0)
1401  {
1402  g_signal_connect(G_OBJECT(spinner), "value_changed",
1403  G_CALLBACK(update_minutes_from_spinner), ui);
1404  }
1405  else if (type == 1)
1406  {
1407  g_signal_connect(G_OBJECT(spinner), "value_changed",
1408  G_CALLBACK(update_seconds_from_spinner), ui);
1409  }
1410  else
1411  {
1412  g_signal_connect(G_OBJECT(spinner), "value_changed",
1413  G_CALLBACK(update_hundr_secs_from_spinner), ui);
1414  }
1415 
1416  gtk_box_pack_start(GTK_BOX(spinner_box), spinner, TRUE, FALSE, 0);
1417  gtk_box_pack_start(GTK_BOX(bottomhbox1), spinner_box, FALSE, FALSE, 5);
1418 
1419  return spinner;
1420 }
1421 
1423 static GtkWidget *create_init_spinners_buttons(ui_state *ui)
1424 {
1425  GtkWidget *hbox = wh_hbox_new();
1426  gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
1427 
1428  //0 means spinner minutes
1429  ui->gui->spinner_minutes = create_init_spinner(hbox, 0, INT_MAX/6000, _("Minutes:"), 0, ui);
1430  //1 means spinner seconds
1431  ui->gui->spinner_seconds = create_init_spinner(hbox, 0, 59, _("Seconds:"), 1, ui);
1432  //2 means spinner hundredth
1433  ui->gui->spinner_hundr_secs = create_init_spinner(hbox, 0, 99, _("Hundredths:"), 2, ui);
1434 
1435  /* add button */
1436  GtkWidget *add_button = wh_create_cool_button(GTK_STOCK_ADD, _("_Add"), FALSE);
1437  ui->gui->add_button = add_button;
1438 
1439  gtk_button_set_relief(GTK_BUTTON(add_button), GTK_RELIEF_NONE);
1440  gtk_widget_set_sensitive(add_button, TRUE);
1441  g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(add_row_clicked), ui);
1442  gtk_box_pack_start(GTK_BOX(hbox), add_button, FALSE, FALSE, 5);
1443  gtk_widget_set_tooltip_text(add_button,_("Add splitpoint"));
1444 
1445  /* remove row button */
1446  GtkWidget *remove_row_button = wh_create_cool_button(GTK_STOCK_REMOVE, _("_Remove"), FALSE);
1447  ui->gui->remove_row_button = remove_row_button;
1448 
1449  gtk_button_set_relief(GTK_BUTTON(remove_row_button), GTK_RELIEF_NONE);
1450  gtk_widget_set_sensitive(remove_row_button, FALSE);
1451  g_signal_connect(G_OBJECT(remove_row_button), "clicked", G_CALLBACK(remove_row), ui);
1452  gtk_box_pack_start(GTK_BOX(hbox), remove_row_button, FALSE, FALSE, 5);
1453  gtk_widget_set_tooltip_text(remove_row_button, _("Remove selected splitpoints"));
1454 
1455  /* remove all rows button */
1456  GtkWidget *remove_all_button = wh_create_cool_button(GTK_STOCK_CLEAR, _("R_emove all"), FALSE);
1457  ui->gui->remove_all_button = remove_all_button;
1458 
1459  gtk_button_set_relief(GTK_BUTTON(remove_all_button), GTK_RELIEF_NONE);
1460  gtk_widget_set_sensitive(remove_all_button, FALSE);
1461  g_signal_connect(G_OBJECT(remove_all_button), "clicked", G_CALLBACK(remove_all_rows), ui);
1462  gtk_box_pack_start(GTK_BOX(hbox), remove_all_button, FALSE, FALSE, 5);
1463  gtk_widget_set_tooltip_text(remove_all_button, _("Remove all splitpoints"));
1464 
1465  return hbox;
1466 }
1467 
1469 static void create_init_special_buttons(ui_state *ui)
1470 {
1471  /* set splitpoints from trim silence detection */
1472  GtkWidget *scan_trim_silence_button =
1473  wh_create_cool_button(GTK_STOCK_CUT, _("_Trim splitpoints"), FALSE);
1474  ui->gui->scan_trim_silence_button = scan_trim_silence_button;
1475  gtk_widget_set_sensitive(scan_trim_silence_button, TRUE);
1476  g_signal_connect(G_OBJECT(scan_trim_silence_button), "clicked",
1477  G_CALLBACK(create_trim_silence_window), ui);
1478  gtk_widget_set_tooltip_text(scan_trim_silence_button,
1479  _("Set trim splitpoints using silence detection"));
1480 
1481  /* set splitpoints from silence detection */
1482  GtkWidget *scan_silence_button =
1483  wh_create_cool_button(GTK_STOCK_FIND_AND_REPLACE, _("_Silence detection"), FALSE);
1484  ui->gui->scan_silence_button = scan_silence_button;
1485  gtk_widget_set_sensitive(scan_silence_button, TRUE);
1486  g_signal_connect(G_OBJECT(scan_silence_button), "clicked",
1488  gtk_widget_set_tooltip_text(scan_silence_button,
1489  _("Set splitpoints from silence detection"));
1490 }
1491 
1496 gchar *get_splitpoint_name(gint index, ui_state *ui)
1497 {
1498  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1499 
1500  gchar *description = NULL;
1501 
1502  GtkTreeIter iter;
1503  if (!gtk_tree_model_get_iter_first(model, &iter))
1504  {
1505  return NULL;
1506  }
1507 
1508  if (index == -1)
1509  {
1510  index = 0;
1511  }
1512 
1513  if (index >= 0)
1514  {
1515  GtkTreePath *path = gtk_tree_path_new_from_indices(index ,-1);
1516  gtk_tree_model_get_iter(model, &iter, path);
1517  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1518  COL_DESCRIPTION, &description,
1519  -1);
1520  gtk_tree_path_free(path);
1521  }
1522 
1523  return description;
1524 }
1525 
1527 gint get_splitpoint_time(gint splitpoint_index, ui_state *ui)
1528 {
1529  if (splitpoint_index < 0 ||
1530  splitpoint_index >= ui->splitpoints->len)
1531  {
1532  return -1;
1533  }
1534 
1535  Split_point point = g_array_index(ui->splitpoints, Split_point, splitpoint_index);
1536  return point.mins * 6000 + point.secs * 100 + point.hundr_secs;
1537 }
1538 
1539 static gboolean split_preview_end(ui_with_err *ui_err)
1540 {
1541  gint err = ui_err->err;
1542  ui_state *ui = ui_err->ui;
1543 
1545 
1546  gchar *split_file = get_filename_from_split_files(1, ui->gui);
1547  if (split_file != NULL && err > 0)
1548  {
1549  connect_button_event(ui->gui->connect_button, ui);
1550 
1551  change_current_filename(split_file, ui);
1552  g_free(split_file);
1553 
1554  //0 means start playing
1556  }
1557 
1558  if (err > 0)
1559  {
1560  gtk_progress_bar_set_fraction(ui->gui->percent_progress_bar, 1.0);
1561  gtk_progress_bar_set_text(ui->gui->percent_progress_bar, _(" finished"));
1562  }
1563 
1564  set_process_in_progress_and_wait_safe(FALSE, ui_err->ui);
1565 
1566  g_free(ui_err);
1567 
1568  return FALSE;
1569 }
1570 
1571 static gpointer split_preview(ui_state *ui)
1572 {
1573  set_process_in_progress_and_wait_safe(TRUE, ui);
1574 
1575  int err = mp3splt_erase_all_splitpoints(ui->mp3splt_state);
1576  err = mp3splt_erase_all_tags(ui->mp3splt_state);
1577 
1578  enter_threads();
1579 
1580  splt_point *splitpoint = mp3splt_point_new(get_preview_start_position_safe(ui), NULL);
1581  mp3splt_point_set_name(splitpoint, "preview");
1583  mp3splt_append_splitpoint(ui->mp3splt_state, splitpoint);
1584 
1585  splitpoint = mp3splt_point_new(
1586  get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui), ui), NULL);
1588  mp3splt_append_splitpoint(ui->mp3splt_state, splitpoint);
1589 
1590  lock_mutex(&ui->variables_mutex);
1591  mp3splt_set_filename_to_split(ui->mp3splt_state, get_input_filename(ui->gui));
1592  unlock_mutex(&ui->variables_mutex);
1593 
1596 
1599 
1600  exit_threads();
1601 
1602  gchar *fname_path = get_preferences_filename();
1603  fname_path[strlen(fname_path) - 18] = '\0';
1604  mp3splt_set_path_of_split(ui->mp3splt_state, fname_path);
1605  if (fname_path) { g_free(fname_path); }
1606 
1607  err = mp3splt_split(ui->mp3splt_state);
1608 
1609  ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
1610  ui_err->err = err;
1611  ui_err->ui = ui;
1612 
1613  gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)split_preview_end, ui_err, NULL);
1614 
1615  return NULL;
1616 }
1617 
1618 static void split_preview_action(ui_state *ui)
1619 {
1620  create_thread((GThreadFunc)split_preview, ui);
1621 }
1622 
1624 static void preview_song(GtkTreeView *tree_view, GtkTreePath *path,
1625  GtkTreeViewColumn *col, ui_state *ui)
1626 {
1627  gint number = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(col), "col"));
1628  if (number != COL_PREVIEW && number != COL_SPLIT_PREVIEW)
1629  {
1630  return;
1631  }
1632 
1633  if (!ui->status->timer_active)
1634  {
1635  put_status_message(_(" cannot preview, not connected to player"), ui);
1636  return;
1637  }
1638 
1639  //get the split begin position to find the end position
1640  gint preview_row = gtk_tree_path_get_indices(path)[0];
1641  ui->status->preview_row = preview_row;
1642  if (number == COL_PREVIEW)
1643  {
1644  player_quick_preview(preview_row, ui);
1645  }
1646  else if (number == COL_SPLIT_PREVIEW)
1647  {
1648  set_preview_start_position_safe(get_splitpoint_time(preview_row, ui), ui);
1649  set_quick_preview_end_splitpoint_safe(preview_row + 1, ui);
1650 
1651  if (ui->status->preview_row + 1 == ui->infos->splitnumber)
1652  {
1653  put_status_message(_(" cannot split preview last splitpoint"), ui);
1654  return;
1655  }
1656 
1657  split_preview_action(ui);
1658  }
1659 }
1660 
1662 static void toggled_splitpoint_event(GtkCellRendererToggle *cell,
1663  gchar *path_str, ui_state *ui)
1664 {
1665  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1666  GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1667  gboolean checked = FALSE;
1668 
1669  GtkTreeIter iter;
1670  gtk_tree_model_get_iter(model, &iter, path);
1671  gtk_tree_model_get(model, &iter, COL_CHECK, &checked, -1);
1672 
1673  //toggle the value
1674  checked ^= 1;
1675 
1676  //get the indice
1677  gint index = gtk_tree_path_get_indices (path)[0];
1678  Split_point new_point;
1679  Split_point old_point;
1680 
1681  //put new 'checked' value to splitpoint
1682  old_point = g_array_index(ui->splitpoints, Split_point, index);
1683  new_point.mins = old_point.mins;
1684  new_point.secs = old_point.secs;
1685  new_point.hundr_secs = old_point.hundr_secs;
1686  new_point.checked = checked;
1687 
1688  update_splitpoint(index, new_point, ui);
1689 
1690  gtk_tree_path_free(path);
1691 }
1692 
1693 static void clone_tag(ui_state *ui, gint column)
1694 {
1695  gui_state *gui = ui->gui;
1696 
1697  GtkTreeModel *model = gtk_tree_view_get_model(gui->tree_view);
1698  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
1699 
1700  GList *selected_list =
1701  gtk_tree_selection_get_selected_rows(GTK_TREE_SELECTION(selection), &model);
1702 
1703  if (g_list_length(selected_list) <= 0)
1704  {
1705  return;
1706  }
1707 
1708  GList *current_element = g_list_first(selected_list);
1709  GtkTreePath *path = current_element->data;
1710  GtkTreeIter iter;
1711  gtk_tree_model_get_iter(model, &iter, path);
1712 
1713  gchar *value = NULL;
1714  gint int_value = 0;
1715  if (column == COL_YEAR || column == COL_TRACK)
1716  {
1717  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, column, &int_value, -1);
1718  }
1719  else
1720  {
1721  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, column, &value, -1);
1722  }
1723 
1724  gint number = 0;
1725  for (number = 0;number < ui->infos->splitnumber; number++)
1726  {
1727  GtkTreePath *path2 = gtk_tree_path_new_from_indices(number ,-1);
1728  GtkTreeIter iter2;
1729  gtk_tree_model_get_iter(model, &iter2, path2);
1730  gtk_tree_path_free(path2);
1731 
1732  if (column == COL_YEAR || column == COL_TRACK)
1733  {
1734  gtk_list_store_set(GTK_LIST_STORE(model), &iter2, column, int_value, -1);
1735  }
1736  else
1737  {
1738  gtk_list_store_set(GTK_LIST_STORE(model), &iter2, column, value, -1);
1739  }
1740  }
1741 
1742  if (value) { g_free(value); }
1743 
1744  g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
1745  g_list_free(selected_list);
1746 }
1747 
1748 static void clone_all_event(GtkMenuItem *menuitem, ui_state *ui)
1749 {
1750  clone_tag(ui, COL_TITLE);
1751  clone_tag(ui, COL_ARTIST);
1752  clone_tag(ui, COL_ALBUM);
1753  clone_tag(ui, COL_GENRE);
1754  clone_tag(ui, COL_YEAR);
1755  clone_tag(ui, COL_TRACK);
1756  clone_tag(ui, COL_COMMENT);
1757 
1758  export_cue_file_in_configuration_directory(ui);
1759 }
1760 
1761 static void clone_title_event(GtkMenuItem *menuitem, ui_state *ui)
1762 {
1763  clone_tag(ui, COL_TITLE);
1764  export_cue_file_in_configuration_directory(ui);
1765 }
1766 
1767 static void clone_artist_event(GtkMenuItem *menuitem, ui_state *ui)
1768 {
1769  clone_tag(ui, COL_ARTIST);
1770  export_cue_file_in_configuration_directory(ui);
1771 }
1772 
1773 static void clone_album_event(GtkMenuItem *menuitem, ui_state *ui)
1774 {
1775  clone_tag(ui, COL_ALBUM);
1776  export_cue_file_in_configuration_directory(ui);
1777 }
1778 
1779 static void clone_genre_event(GtkMenuItem *menuitem, ui_state *ui)
1780 {
1781  clone_tag(ui, COL_GENRE);
1782  export_cue_file_in_configuration_directory(ui);
1783 }
1784 
1785 static void clone_year_event(GtkMenuItem *menuitem, ui_state *ui)
1786 {
1787  clone_tag(ui, COL_YEAR);
1788  export_cue_file_in_configuration_directory(ui);
1789 }
1790 
1791 static void clone_track_event(GtkMenuItem *menuitem, ui_state *ui)
1792 {
1793  clone_tag(ui, COL_TRACK);
1794  export_cue_file_in_configuration_directory(ui);
1795 }
1796 
1797 static void clone_comment_event(GtkMenuItem *menuitem, ui_state *ui)
1798 {
1799  clone_tag(ui, COL_COMMENT);
1800  export_cue_file_in_configuration_directory(ui);
1801 }
1802 
1803 static void auto_increment_track_event(GtkMenuItem *menuitem, ui_state *ui)
1804 {
1805  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1806 
1807  gint number = 0;
1808  for (number = 0;number < ui->infos->splitnumber; number++)
1809  {
1810  GtkTreePath *path2 = gtk_tree_path_new_from_indices(number ,-1);
1811  GtkTreeIter iter2;
1812  gtk_tree_model_get_iter(model, &iter2, path2);
1813  gtk_tree_path_free(path2);
1814  gtk_list_store_set(GTK_LIST_STORE(model), &iter2, COL_TRACK, GINT_TO_POINTER(number + 1), -1);
1815  }
1816 
1817  export_cue_file_in_configuration_directory(ui);
1818 }
1819 
1820 static void build_and_show_popup_menu(GtkWidget *treeview, GdkEventButton *event, ui_state *ui)
1821 {
1822  GtkWidget *menu = gtk_menu_new();
1823 
1824  GtkWidget *item = gtk_image_menu_item_new_with_label(_("Clone all tags"));
1825  GtkWidget *image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1826  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1827  g_signal_connect(item, "activate", G_CALLBACK(clone_all_event), ui);
1828  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1829 
1830  gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1831 
1832  item = gtk_image_menu_item_new_with_label(_("Clone title"));
1833  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1834  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1835  g_signal_connect(item, "activate", G_CALLBACK(clone_title_event), ui);
1836  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1837 
1838  item = gtk_image_menu_item_new_with_label(_("Clone artist"));
1839  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1840  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1841  g_signal_connect(item, "activate", G_CALLBACK(clone_artist_event), ui);
1842  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1843 
1844  item = gtk_image_menu_item_new_with_label(_("Clone album"));
1845  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1846  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1847  g_signal_connect(item, "activate", G_CALLBACK(clone_album_event), ui);
1848  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1849 
1850  item = gtk_image_menu_item_new_with_label(_("Clone genre"));
1851  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1852  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1853  g_signal_connect(item, "activate", G_CALLBACK(clone_genre_event), ui);
1854  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1855 
1856  item = gtk_image_menu_item_new_with_label(_("Clone year"));
1857  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1858  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1859  g_signal_connect(item, "activate", G_CALLBACK(clone_year_event), ui);
1860  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1861 
1862  item = gtk_image_menu_item_new_with_label(_("Clone track"));
1863  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1864  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1865  g_signal_connect(item, "activate", G_CALLBACK(clone_track_event), ui);
1866  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1867 
1868  item = gtk_image_menu_item_new_with_label(_("Clone comment"));
1869  image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
1870  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1871  g_signal_connect(item, "activate", G_CALLBACK(clone_comment_event), ui);
1872  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1873 
1874  gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1875 
1876  item = gtk_image_menu_item_new_with_label(_("Auto-increment track"));
1877  image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU);
1878  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1879  g_signal_connect(item, "activate", G_CALLBACK(auto_increment_track_event), ui);
1880  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1881 
1882  gtk_widget_show_all(menu);
1883 
1884  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1885  (event != NULL) ? event->button : 0, gdk_event_get_time((GdkEvent*)event));
1886 }
1887 
1888 static gboolean show_popup(GtkWidget *treeview, ui_state *ui)
1889 {
1890  build_and_show_popup_menu(treeview, NULL, ui);
1891  return TRUE;
1892 }
1893 
1894 static gboolean select_and_show_popup(GtkWidget *treeview, GdkEventButton *event, ui_state *ui)
1895 {
1896  if (event->type != GDK_BUTTON_PRESS || event->button != 3)
1897  {
1898  return FALSE;
1899  }
1900 
1901  GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1902  if (gtk_tree_selection_count_selected_rows(selection) <= 1)
1903  {
1904  GtkTreePath *path;
1905  if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
1906  (gint) event->x, (gint) event->y, &path, NULL, NULL, NULL))
1907  {
1908  gtk_tree_selection_unselect_all(selection);
1909  gtk_tree_selection_select_path(selection, path);
1910  gtk_tree_path_free(path);
1911  }
1912  else
1913  {
1914  return FALSE;
1915  }
1916  }
1917 
1918  build_and_show_popup_menu(treeview, event, ui);
1919 
1920  return TRUE;
1921 }
1922 
1924 static void create_columns(ui_state *ui)
1925 {
1926  gui_state *gui = ui->gui;
1927 
1928  GtkTreeView *tree_view = gui->tree_view;
1929 
1930  GtkCellRendererText *renderer;
1931  GtkCellRendererPixbuf *renderer_pix;
1932  GtkCellRendererToggle *renderer_toggle;
1933 
1934  GtkTreeViewColumn *column_number;
1935  GtkTreeViewColumn *column_check = NULL;
1936  GtkTreeViewColumn *column_description;
1937  GtkTreeViewColumn *column_hundr_secs;
1938  GtkTreeViewColumn *column_minutes;
1939  GtkTreeViewColumn *column_seconds;
1940  GtkTreeViewColumn *column_preview;
1941  GtkTreeViewColumn *column_split_preview;
1942 
1943  /* Check point / skip point */
1944  renderer_toggle = GTK_CELL_RENDERER_TOGGLE(gtk_cell_renderer_toggle_new());
1945  g_signal_connect(renderer_toggle, "toggled", G_CALLBACK(toggled_splitpoint_event), ui);
1946  g_object_set_data(G_OBJECT(renderer_toggle), "col", GINT_TO_POINTER(COL_CHECK));
1947  column_check = gtk_tree_view_column_new_with_attributes
1948  (_("Keep"), GTK_CELL_RENDERER(renderer_toggle), "active", COL_CHECK, NULL);
1949 
1950  /* description */
1951  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1952  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1953  g_object_set(renderer, "editable", TRUE, NULL);
1954  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_DESCRIPTION));
1955  column_description = gtk_tree_view_column_new_with_attributes
1956  (_("Filename"), GTK_CELL_RENDERER(renderer), "text", COL_DESCRIPTION, NULL);
1957 
1958  /* seconds */
1959  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1960  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1961  g_object_set(renderer, "editable", TRUE, NULL);
1962  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_SECONDS));
1963  column_seconds = gtk_tree_view_column_new_with_attributes
1964  (_("Secs"), GTK_CELL_RENDERER(renderer), "text", COL_SECONDS, NULL);
1965 
1966  /* minutes */
1967  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1968  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1969  g_object_set(renderer, "editable", TRUE, NULL);
1970  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_MINUTES));
1971  column_minutes = gtk_tree_view_column_new_with_attributes
1972  (_("Mins"), GTK_CELL_RENDERER(renderer), "text", COL_MINUTES, NULL);
1973 
1974  /* hundr secs */
1975  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1976  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1977  g_object_set(renderer, "editable", TRUE, NULL);
1978  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_HUNDR_SECS));
1979  column_hundr_secs = gtk_tree_view_column_new_with_attributes
1980  (_("Hundr"), GTK_CELL_RENDERER(renderer), "text", COL_HUNDR_SECS, NULL);
1981 
1982  /* Length column */
1983  //renderer creation
1984  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1985  g_object_set(G_OBJECT (renderer), "xalign", 1.0, NULL);
1986  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_NUMBER));
1987  column_number = gtk_tree_view_column_new_with_attributes
1988  (_("Length"), GTK_CELL_RENDERER(renderer), "text", COL_NUMBER, NULL);
1989 
1990  /* column preview */
1991  renderer_pix = GTK_CELL_RENDERER_PIXBUF(gtk_cell_renderer_pixbuf_new());
1992  g_object_set(renderer_pix, "stock-id", GTK_STOCK_MEDIA_PLAY,
1993  "stock-size", GTK_ICON_SIZE_MENU, NULL);
1994  column_preview = gtk_tree_view_column_new_with_attributes
1995  (_("LiveP"), GTK_CELL_RENDERER(renderer_pix), NULL);
1996  g_object_set_data(G_OBJECT(column_preview), "col", GINT_TO_POINTER(COL_PREVIEW));
1997 
1998  /* split preview */
1999  renderer_pix = GTK_CELL_RENDERER_PIXBUF(gtk_cell_renderer_pixbuf_new());
2000  g_object_set(renderer_pix, "stock-id", GTK_STOCK_MEDIA_PLAY,
2001  "stock-size", GTK_ICON_SIZE_MENU, NULL);
2002  column_split_preview = gtk_tree_view_column_new_with_attributes
2003  (_("SplitP"), GTK_CELL_RENDERER(renderer_pix), NULL);
2004  g_object_set_data(G_OBJECT(column_split_preview), "col", GINT_TO_POINTER(COL_SPLIT_PREVIEW));
2005 
2006  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_check, COL_CHECK);
2007  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_description, COL_DESCRIPTION);
2008  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_minutes, COL_MINUTES);
2009  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_seconds, COL_SECONDS);
2010  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_hundr_secs, COL_HUNDR_SECS);
2011  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_number, COL_NUMBER);
2012  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_preview, COL_PREVIEW);
2013  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_split_preview, COL_SPLIT_PREVIEW);
2014 
2015  gtk_tree_view_column_set_alignment(column_check, 0.5);
2016  gtk_tree_view_column_set_alignment(column_description, 0.5);
2017  gtk_tree_view_column_set_alignment(column_minutes, 0.5);
2018  gtk_tree_view_column_set_alignment(column_seconds, 0.5);
2019  gtk_tree_view_column_set_alignment(column_hundr_secs, 0.5);
2020  gtk_tree_view_column_set_alignment(column_number, 0.5);
2021  gtk_tree_view_column_set_alignment(column_preview, 0.5);
2022  gtk_tree_view_column_set_alignment(column_split_preview, 0.5);
2023 
2024  gtk_tree_view_column_set_sizing(column_check, GTK_TREE_VIEW_COLUMN_FIXED);
2025  gtk_tree_view_column_set_fixed_width(column_check, 70);
2026 
2027  gtk_tree_view_column_set_resizable(column_description, TRUE);
2028 
2029  gtk_tree_view_column_set_reorderable(column_check, TRUE);
2030  gtk_tree_view_column_set_reorderable(column_description, TRUE);
2031  gtk_tree_view_column_set_reorderable(column_minutes, TRUE);
2032  gtk_tree_view_column_set_reorderable(column_seconds, TRUE);
2033  gtk_tree_view_column_set_reorderable(column_hundr_secs, TRUE);
2034  gtk_tree_view_column_set_reorderable(column_number, TRUE);
2035  gtk_tree_view_column_set_reorderable(column_preview, TRUE);
2036  gtk_tree_view_column_set_reorderable(column_split_preview, TRUE);
2037 
2038  gtk_tree_view_column_set_expand(column_description, TRUE);
2039 
2040  gint i = 0;
2041  for (i = COL_TITLE;i < NUM_COLUMNS;i++)
2042  {
2043  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
2044  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
2045  g_object_set(renderer, "editable", TRUE, NULL);
2046  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(i));
2047 
2048  gchar column_name[255] = { '\0' };
2049  gint minimum_width = 100;
2050  switch (i)
2051  {
2052  case COL_TITLE:
2053  g_snprintf(column_name, 255, _("Title"));
2054  break;
2055  case COL_ARTIST:
2056  g_snprintf(column_name, 255, _("Artist"));
2057  break;
2058  case COL_ALBUM:
2059  g_snprintf(column_name, 255, _("Album"));
2060  break;
2061  case COL_GENRE:
2062  g_snprintf(column_name, 255, _("Genre"));
2063  minimum_width = 70;
2064  break;
2065  case COL_COMMENT:
2066  g_snprintf(column_name, 255, _("Comment"));
2067  break;
2068  case COL_YEAR:
2069  g_snprintf(column_name, 255, _("Year"));
2070  minimum_width = 40;
2071  break;
2072  case COL_TRACK:
2073  g_snprintf(column_name, 255, _("Track"));
2074  minimum_width = 20;
2075  break;
2076  }
2077 
2078  GtkTreeViewColumn *tag_column = gtk_tree_view_column_new_with_attributes
2079  (column_name, GTK_CELL_RENDERER(renderer), "text", i, NULL);
2080 
2081  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), tag_column, i);
2082  gtk_tree_view_column_set_alignment(tag_column, 0.5);
2083  gtk_tree_view_column_set_resizable(tag_column, TRUE);
2084  gtk_tree_view_column_set_reorderable(tag_column, TRUE);
2085  gtk_tree_view_column_set_min_width(tag_column, minimum_width);
2086  }
2087 }
2088 
2090 static void create_tree_view(ui_state *ui)
2091 {
2092  GtkTreeView *tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(create_model()));
2093  dnd_add_drag_data_received_to_widget(GTK_WIDGET(tree_view), DND_DATA_FILES, ui);
2094 
2095  ui->gui->tree_view = tree_view;
2096 
2097  g_signal_connect(tree_view, "row-activated", G_CALLBACK(preview_song), ui);
2098 
2099  GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
2100  g_signal_connect(selection, "changed", G_CALLBACK(row_selection_event), ui);
2101 }
2102 
2109 {
2110  gui_state *gui = ui->gui;
2111 
2112  create_tree_view(ui);
2113 
2114  /* choose splitpoins vbox */
2115  GtkWidget *choose_splitpoints_vbox = wh_vbox_new();
2116  gtk_container_set_border_width(GTK_CONTAINER(choose_splitpoints_vbox), 0);
2117 
2118  /* spinner buttons hbox */
2119  GtkWidget *spinners_buttons_hbox = create_init_spinners_buttons(ui);
2120  gtk_box_pack_start(GTK_BOX(choose_splitpoints_vbox), spinners_buttons_hbox, FALSE, FALSE, 3);
2121 
2122  /* horizontal box for the tree */
2123  GtkWidget *tree_hbox = wh_hbox_new();
2124  gtk_box_pack_start(GTK_BOX(choose_splitpoints_vbox), tree_hbox, TRUE, TRUE, 0);
2125 
2126  /* scrolled window for the tree */
2127  GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2128  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_NONE);
2129  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2130  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2131  gtk_box_pack_start(GTK_BOX(tree_hbox), scrolled_window, TRUE, TRUE, 0);
2132 
2133  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
2134  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
2135  create_columns(ui);
2136  gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(gui->tree_view));
2137 
2138  g_signal_connect(gui->tree_view, "popup-menu", G_CALLBACK(show_popup), ui);
2139  g_signal_connect(gui->tree_view, "button-press-event", G_CALLBACK(select_and_show_popup), ui);
2140 
2141  /* special buttons like 'set silence from silence detection' */
2142  create_init_special_buttons(ui);
2143 
2144  return choose_splitpoints_vbox;
2145 }
2146 
2147 static void garray_to_array(GArray *spltpoints, glong *hundredth, ui_state *ui)
2148 {
2149  gint i = 0;
2150  for(i = 0; i < ui->infos->splitnumber; i++ )
2151  {
2152  Split_point point = g_array_index(ui->splitpoints, Split_point, i);
2153  if (point.mins >= (INT_MAX-1)/6000)
2154  {
2155  hundredth[i] = LONG_MAX;
2156  }
2157  else
2158  {
2159  hundredth[i] = point.mins * 6000 +
2160  point.secs * 100 + point.hundr_secs;
2161  }
2162  }
2163 }
2164 
2167 {
2168  glong hundr[ui->infos->splitnumber];
2169  garray_to_array(ui->splitpoints, hundr, ui);
2170 
2171  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
2172 
2173  gint i;
2174  for (i = 0; i < ui->infos->splitnumber; i++)
2175  {
2176  GtkTreePath *path = gtk_tree_path_new_from_indices(i ,-1);
2177  GtkTreeIter iter;
2178  gtk_tree_model_get_iter(model, &iter, path);
2179  gtk_tree_path_free(path);
2180 
2181  gchar *description = NULL;
2182  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, COL_DESCRIPTION, &description, -1);
2183 
2184  //get the 'checked' value from the current splitpoint
2185  Split_point point = g_array_index(ui->splitpoints, Split_point, i);
2186  gint splitpoint_type = SPLT_SPLITPOINT;
2187 
2188  if (point.checked == FALSE)
2189  {
2190  splitpoint_type = SPLT_SKIPPOINT;
2191  }
2192 
2193  splt_point *splitpoint = mp3splt_point_new(hundr[i], NULL);
2194  mp3splt_point_set_name(splitpoint, description);
2195  g_free(description);
2196  mp3splt_point_set_type(splitpoint, splitpoint_type);
2197  mp3splt_append_splitpoint(state, splitpoint);
2198 
2199  gint year = 0, track = 0;
2200  gchar *title = NULL, *artist = NULL, *album = NULL, *genre = NULL, *comment = NULL;
2201 
2202  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
2203  COL_TITLE, &title,
2204  COL_ARTIST, &artist,
2205  COL_ALBUM, &album,
2206  COL_GENRE, &genre,
2207  COL_COMMENT, &comment,
2208  COL_YEAR, &year,
2209  COL_TRACK, &track,
2210  -1);
2211 
2212  splt_tags *tags = mp3splt_tags_new(NULL);
2213 
2214  if (year > 0)
2215  {
2216  gchar year_str[10] = { '\0' };
2217  g_snprintf(year_str, 10, "%d", year);
2218  mp3splt_tags_set(tags, SPLT_TAGS_YEAR, year_str, 0);
2219  }
2220 
2221  if (track <= 0) { track = -2; }
2222  gchar track_str[10] = { '\0' };
2223  g_snprintf(track_str, 10, "%d", track);
2224  mp3splt_tags_set(tags, SPLT_TAGS_TRACK, track_str, 0);
2225 
2226  mp3splt_tags_set(tags,
2227  SPLT_TAGS_TITLE, title,
2228  SPLT_TAGS_ARTIST, artist,
2229  SPLT_TAGS_ALBUM, album,
2230  SPLT_TAGS_GENRE, genre,
2231  SPLT_TAGS_COMMENT, comment,
2232  0);
2233  mp3splt_append_tags(state, tags);
2234 
2235  free(title); free(artist); free(album); free(genre); free(comment);
2236  }
2237 }
2238 
2239