~ubuntu-branches/ubuntu/hardy/gtkpod-aac/hardy

« back to all changes in this revision

Viewing changes to src/display_songs.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-07-17 18:25:25 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070717182525-rhl5w4pk8lbk6pna
Tags: 0.99.10-2ubuntu1
* Resynchronise with gtkpod 0.9.10-2.
* Hack in dpatch support, since it was removed.
* Rename debian/patches/03-configure.dpatch to
  debian/patches/aac-configure.dpatch.
* Update debian/gtkpod-aac.diff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Time-stamp: <2006-06-23 23:52:48 jcs>
2
 
|
3
 
|  Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
4
 
|  Part of the gtkpod project.
5
 
|
6
 
|  URL: http://www.gtkpod.org/
7
 
|  URL: http://gtkpod.sourceforge.net/
8
 
|
9
 
|  This program is free software; you can redistribute it and/or modify
10
 
|  it under the terms of the GNU General Public License as published by
11
 
|  the Free Software Foundation; either version 2 of the License, or
12
 
|  (at your option) any later version.
13
 
|
14
 
|  This program is distributed in the hope that it will be useful,
15
 
|  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
|  GNU General Public License for more details.
18
 
|
19
 
|  You should have received a copy of the GNU General Public License
20
 
|  along with this program; if not, write to the Free Software
21
 
|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
 
|
23
 
|  iTunes and iPod are trademarks of Apple
24
 
|
25
 
|  This product is not supported/written/published by Apple!
26
 
|
27
 
|  $Id: display_songs.c,v 1.112 2006/09/21 15:03:13 jcsjcs Exp $
28
 
*/
29
 
 
30
 
#ifdef HAVE_CONFIG_H
31
 
#  include <config.h>
32
 
#endif
33
 
 
34
 
#include <gdk/gdkkeysyms.h>
35
 
#include <gtk/gtk.h>
36
 
#include <limits.h>
37
 
#include <stdio.h>
38
 
#include <stdlib.h>
39
 
#include <string.h>
40
 
#include <sys/stat.h>
41
 
#include <sys/types.h>
42
 
#include <unistd.h>
43
 
 
44
 
#include "prefs.h"
45
 
#include "display_private.h"
46
 
#include "display_itdb.h"
47
 
#include "itdb.h"
48
 
#include "info.h"
49
 
#include "misc.h"
50
 
#include "misc_track.h"
51
 
#include "file.h"
52
 
#include "context_menus.h"
53
 
 
54
 
/* pointer to the treeview for the track display */
55
 
static GtkTreeView *track_treeview = NULL;
56
 
/* array with pointers to the columns used in the track display */
57
 
static GtkTreeViewColumn *tm_columns[TM_NUM_COLUMNS];
58
 
/* column in which track pointer is stored */
59
 
static const gint READOUT_COL = 0;
60
 
 
61
 
/* compare function to be used for string comparisons */
62
 
static gint (*string_compare_func) (const gchar *str1, const gchar *str2) = compare_string;
63
 
 
64
 
static GtkTreeViewColumn *tm_add_column (TM_item tm_item, gint position);
65
 
static TM_item tm_lookup_col_id (GtkTreeViewColumn *column);
66
 
 
67
 
/* Drag and drop definitions */
68
 
static GtkTargetEntry tm_drag_types [] = {
69
 
    { DND_GTKPOD_TM_PATHLIST_TYPE, 0, DND_GTKPOD_TM_PATHLIST },
70
 
    { DND_GTKPOD_TRACKLIST_TYPE, 0, DND_GTKPOD_TRACKLIST },
71
 
    { "text/uri-list", 0, DND_TEXT_URI_LIST },
72
 
    { "text/plain", 0, DND_TEXT_PLAIN },
73
 
    { "STRING", 0, DND_TEXT_PLAIN }
74
 
};
75
 
static GtkTargetEntry tm_drop_types [] = {
76
 
    { DND_GTKPOD_TM_PATHLIST_TYPE, 0, DND_GTKPOD_TM_PATHLIST },
77
 
    { "text/uri-list", 0, DND_TEXT_URI_LIST },
78
 
    { "text/plain", 0, DND_TEXT_PLAIN },
79
 
    { "STRING", 0, DND_TEXT_PLAIN }
80
 
};
81
 
 
82
 
/* prefs strings */
83
 
const gchar *TM_PREFS_SEARCH_COLUMN = "tm_prefs_search_column";
84
 
 
85
 
 
86
 
/* ---------------------------------------------------------------- */
87
 
/* Section for track display                                        */
88
 
/* DND -- Drag And Drop                                             */
89
 
/* ---------------------------------------------------------------- */
90
 
 
91
 
 
92
 
/* Move the paths listed in @data before or after (according to @pos)
93
 
   @path. Used for DND */
94
 
static gboolean tm_move_pathlist (gchar *data,
95
 
                                  GtkTreePath *path,
96
 
                                  GtkTreeViewDropPosition pos)
97
 
{
98
 
    GtkTreeIter to_iter;
99
 
    GtkTreeIter *from_iter;
100
 
    GtkTreeModel *model;
101
 
    GList *iterlist = NULL;
102
 
    GList *link;
103
 
    gchar **paths, **pathp;
104
 
 
105
 
    g_return_val_if_fail (data, FALSE);
106
 
    g_return_val_if_fail (*data, FALSE);
107
 
 
108
 
    model = gtk_tree_view_get_model (track_treeview);
109
 
    g_return_val_if_fail (model, FALSE);
110
 
 
111
 
    g_return_val_if_fail (gtk_tree_model_get_iter (model, &to_iter, path),
112
 
                          FALSE);
113
 
 
114
 
    /* split the path list into individual strings */
115
 
    paths = g_strsplit (data, "\n", -1);
116
 
    pathp = paths;
117
 
    /* Convert the list of paths into a list of iters */
118
 
    while (*pathp)
119
 
    {
120
 
        from_iter = g_malloc (sizeof (GtkTreeIter));
121
 
        if ((strlen (*pathp) > 0) &&
122
 
            gtk_tree_model_get_iter_from_string (model, from_iter, *pathp))
123
 
        {
124
 
            iterlist = g_list_append (iterlist, from_iter);
125
 
        }
126
 
        ++pathp;
127
 
    }
128
 
    g_strfreev (paths);
129
 
    /* Move the iters in iterlist before or after @to_iter */
130
 
    switch (pos)
131
 
    {
132
 
    case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
133
 
    case GTK_TREE_VIEW_DROP_AFTER:
134
 
        for (link = g_list_last (iterlist); link; link = link->prev)
135
 
        {
136
 
            from_iter = (GtkTreeIter *)link->data;
137
 
            gtk_list_store_move_after (GTK_LIST_STORE (model),
138
 
                                       from_iter, &to_iter);
139
 
        }
140
 
        break;
141
 
    case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
142
 
    case GTK_TREE_VIEW_DROP_BEFORE:
143
 
        for (link = g_list_first (iterlist); link; link = link->next)
144
 
        {
145
 
            from_iter = (GtkTreeIter *)link->data;
146
 
            gtk_list_store_move_before (GTK_LIST_STORE (model),
147
 
                                        from_iter, &to_iter);
148
 
        }
149
 
        break;
150
 
    }
151
 
 
152
 
    /* free iterlist */
153
 
    for (link = iterlist; link; link = link->next)
154
 
        g_free (link->data);
155
 
    g_list_free (iterlist);
156
 
 
157
 
    tm_rows_reordered ();
158
 
    return TRUE;
159
 
}
160
 
 
161
 
 
162
 
/*
163
 
 * utility function for appending ipod track ids for track view (DND)
164
 
 */
165
 
static void
166
 
on_tm_dnd_get_track_foreach(GtkTreeModel *tm, GtkTreePath *tp,
167
 
                            GtkTreeIter *i, gpointer data)
168
 
{
169
 
    Track *tr;
170
 
    GString *tracklist = (GString *)data;
171
 
 
172
 
    g_return_if_fail (tracklist);
173
 
 
174
 
    gtk_tree_model_get(tm, i, READOUT_COL, &tr, -1);
175
 
    g_return_if_fail (tr);
176
 
 
177
 
    g_string_append_printf (tracklist, "%p\n", tr);
178
 
}
179
 
 
180
 
 
181
 
/*
182
 
 * utility function for appending path for track view (DND)
183
 
 */
184
 
static void
185
 
on_tm_dnd_get_path_foreach(GtkTreeModel *tm, GtkTreePath *tp,
186
 
                           GtkTreeIter *iter, gpointer data)
187
 
{
188
 
    GString *filelist = (GString *)data;
189
 
    gchar *ps = gtk_tree_path_to_string (tp);
190
 
    g_string_append_printf (filelist, "%s\n", ps);
191
 
    g_free (ps);
192
 
}
193
 
 
194
 
/*
195
 
 * utility function for appending file for track view (DND)
196
 
 */
197
 
static void
198
 
on_tm_dnd_get_file_foreach(GtkTreeModel *tm, GtkTreePath *tp,
199
 
                           GtkTreeIter *iter, gpointer data)
200
 
{
201
 
    Track *track;
202
 
    GString *filelist = (GString *)data;
203
 
    gchar *name;
204
 
 
205
 
    gtk_tree_model_get(tm, iter, READOUT_COL, &track, -1);
206
 
    name = get_file_name_from_source (track, SOURCE_PREFER_LOCAL);
207
 
    if (name)
208
 
    {
209
 
        g_string_append_printf (filelist, "file:%s\n", name);
210
 
        g_free (name);
211
 
    }
212
 
}
213
 
 
214
 
/*
215
 
 * utility function for appending file-uri for track view (DND)
216
 
 */
217
 
static void
218
 
on_tm_dnd_get_uri_foreach(GtkTreeModel *tm, GtkTreePath *tp,
219
 
                          GtkTreeIter *iter, gpointer data)
220
 
{
221
 
    Track *track;
222
 
    GString *filelist = (GString *)data;
223
 
    gchar *name;
224
 
 
225
 
    gtk_tree_model_get(tm, iter, READOUT_COL, &track, -1);
226
 
    name = get_file_name_from_source (track, SOURCE_PREFER_LOCAL);
227
 
    if (name)
228
 
    {
229
 
        gchar *uri = g_filename_to_uri (name, NULL, NULL);
230
 
        if (uri)
231
 
        {
232
 
            g_string_append_printf (filelist, "%s\n", uri);
233
 
            g_free (uri);
234
 
        }
235
 
        g_free (name);
236
 
    }
237
 
}
238
 
 
239
 
static void tm_drag_begin (GtkWidget *widget,
240
 
                           GdkDragContext *dc,
241
 
                           gpointer user_data)
242
 
{
243
 
/*     puts ("tm_drag_begin"); */
244
 
}
245
 
 
246
 
 
247
 
/* remove dragged playlist after successful MOVE */
248
 
static void tm_drag_data_delete (GtkWidget *widget,
249
 
                           GdkDragContext *dc,
250
 
                           gpointer user_data)
251
 
{
252
 
    GtkTreeSelection *ts;
253
 
    Playlist *pl = pm_get_selected_playlist ();
254
 
    gint num;
255
 
 
256
 
/*     puts ("tm_drag_data_delete"); */
257
 
 
258
 
    g_return_if_fail (widget);
259
 
    ts = gtk_tree_view_get_selection (GTK_TREE_VIEW(widget));
260
 
    g_return_if_fail (ts);
261
 
    /* number of selected tracks */
262
 
    num = gtk_tree_selection_count_selected_rows (ts);
263
 
    if (num == 0) return;
264
 
 
265
 
    /* Check if we really have to delete the tracks */
266
 
    if (!itdb_playlist_is_mpl (pl))
267
 
    {   /* get list of selected tracks */
268
 
        GString *reply = g_string_sized_new (2000);
269
 
        gchar *str;
270
 
        Track *track;
271
 
 
272
 
        gtk_tree_selection_selected_foreach(ts,
273
 
                                            on_tm_dnd_get_track_foreach,
274
 
                                            reply);
275
 
        str = reply->str;
276
 
        while(parse_tracks_from_string(&str, &track))
277
 
        {
278
 
            gp_playlist_remove_track (pl, track, DELETE_ACTION_PLAYLIST);
279
 
        }
280
 
        g_string_free (reply, TRUE);
281
 
 
282
 
        gtkpod_statusbar_message (ngettext ("Moved one track",
283
 
                                            "Moved %d tracks", num), num);
284
 
    }
285
 
    else
286
 
    {
287
 
        gtkpod_statusbar_message (ngettext ("Copied one track",
288
 
                                            "Copied %d tracks", num), num);
289
 
    }
290
 
}
291
 
 
292
 
 
293
 
 
294
 
static void tm_drag_end (GtkWidget *widget,
295
 
                         GdkDragContext *dc,
296
 
                         gpointer user_data)
297
 
{
298
 
/*     puts ("tm_drag_end"); */
299
 
    display_remove_autoscroll_row_timeout (widget);
300
 
    gtkpod_tracks_statusbar_update ();
301
 
}
302
 
 
303
 
 
304
 
static gboolean tm_drag_drop (GtkWidget *widget,
305
 
                              GdkDragContext *dc,
306
 
                              gint x,
307
 
                              gint y,
308
 
                              guint time,
309
 
                              gpointer user_data)
310
 
{
311
 
    GdkAtom target;
312
 
 
313
 
/*     puts ("tm_drag_data_drop"); */
314
 
 
315
 
    display_remove_autoscroll_row_timeout (widget);
316
 
 
317
 
    target = gtk_drag_dest_find_target (widget, dc, NULL);
318
 
 
319
 
    if (target != GDK_NONE)
320
 
    {
321
 
        gtk_drag_get_data (widget, dc, target, time);
322
 
        return TRUE;
323
 
    }
324
 
    return FALSE;
325
 
}
326
 
 
327
 
static void tm_drag_leave (GtkWidget *widget,
328
 
                           GdkDragContext *dc,
329
 
                           guint time,
330
 
                           gpointer user_data)
331
 
{
332
 
/*     puts ("tm_drag_leave"); */
333
 
    display_remove_autoscroll_row_timeout (widget);
334
 
}
335
 
 
336
 
 
337
 
 
338
 
static gboolean tm_drag_motion (GtkWidget *widget,
339
 
                                GdkDragContext *dc,
340
 
                                gint x,
341
 
                                gint y,
342
 
                                guint time,
343
 
                                gpointer user_data)
344
 
{
345
 
    GtkTreeView *treeview;
346
 
    GdkAtom target;
347
 
    GtkTreePath *path = NULL;
348
 
    GtkTreeViewDropPosition pos;
349
 
 
350
 
/*     printf ("drag_motion  suggested: %d actions: %d\n", */
351
 
/*          dc->suggested_action, dc->actions); */
352
 
 
353
 
/*     printf ("x: %d y: %d\n", x, y); */
354
 
 
355
 
    g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
356
 
 
357
 
    treeview = GTK_TREE_VIEW (widget);
358
 
 
359
 
    display_install_autoscroll_row_timeout (widget);
360
 
 
361
 
    /* optically set destination row if available */
362
 
    if (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
363
 
                                           x, y, &path, &pos))
364
 
    {
365
 
        /* drops are only allowed before and after -- not onto
366
 
           existing paths */
367
 
        switch (pos)
368
 
        {
369
 
        case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
370
 
        case GTK_TREE_VIEW_DROP_AFTER:
371
 
            gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), path,
372
 
                                             GTK_TREE_VIEW_DROP_AFTER);
373
 
            break;
374
 
        case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
375
 
        case GTK_TREE_VIEW_DROP_BEFORE:
376
 
            gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), path,
377
 
                                             GTK_TREE_VIEW_DROP_BEFORE);
378
 
            break;
379
 
        }
380
 
 
381
 
        gtk_tree_path_free (path);
382
 
        path = NULL;
383
 
    }
384
 
    else
385
 
    {
386
 
        path = gtk_tree_path_new_first ();
387
 
        gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), path,
388
 
                                         GTK_TREE_VIEW_DROP_BEFORE);
389
 
        gtk_tree_path_free (path);
390
 
        path = NULL;
391
 
    }
392
 
 
393
 
 
394
 
 
395
 
    if (pm_get_selected_playlist () == NULL)
396
 
    {   /* no drop possible if no playlist is selected */
397
 
        gdk_drag_status (dc, 0, time);
398
 
        return FALSE;
399
 
    }
400
 
 
401
 
    target = gtk_drag_dest_find_target (widget, dc, NULL);
402
 
 
403
 
    /* no drop possible if no valid target can be found */
404
 
    if (target == GDK_NONE)
405
 
    {
406
 
        gdk_drag_status (dc, 0, time);
407
 
        return FALSE;
408
 
    }
409
 
 
410
 
    if (widget == gtk_drag_get_source_widget (dc))
411
 
    {   /* drag is within the same widget */
412
 
        gint column;
413
 
        GtkSortType order;
414
 
        GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
415
 
        g_return_val_if_fail (model, FALSE);
416
 
        if(gtk_tree_sortable_get_sort_column_id (
417
 
               GTK_TREE_SORTABLE (model), &column, &order))
418
 
        {   /* don't allow move because the model is sorted */
419
 
            gdk_drag_status (dc, 0, time);
420
 
            return FALSE;
421
 
        }
422
 
        else
423
 
        {   /* only allow moves within the same widget */
424
 
            gdk_drag_status (dc, GDK_ACTION_MOVE, time);
425
 
        }
426
 
    }
427
 
    else
428
 
    {  /* whatever the source suggests */
429
 
        gdk_drag_status (dc, dc->suggested_action, time);
430
 
    }
431
 
 
432
 
    return TRUE;
433
 
}
434
 
 
435
 
 
436
 
static void tm_drag_data_get (GtkWidget       *widget,
437
 
                              GdkDragContext  *context,
438
 
                              GtkSelectionData *data,
439
 
                              guint            info,
440
 
                              guint            time,
441
 
                              gpointer         user_data)
442
 
{
443
 
    GtkTreeSelection *ts = NULL;
444
 
    GString *reply = g_string_sized_new (2000);
445
 
 
446
 
/*     printf("tm drag get info: %d\n", info); */
447
 
    if((data) && (ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget))))
448
 
    {
449
 
        switch (info)
450
 
        {
451
 
        case DND_GTKPOD_TRACKLIST:
452
 
            gtk_tree_selection_selected_foreach(ts,
453
 
                                    on_tm_dnd_get_track_foreach, reply);
454
 
            break;
455
 
        case DND_GTKPOD_TM_PATHLIST:
456
 
            gtk_tree_selection_selected_foreach(ts,
457
 
                                    on_tm_dnd_get_path_foreach, reply);
458
 
            break;
459
 
        case DND_TEXT_URI_LIST:
460
 
            gtk_tree_selection_selected_foreach(ts,
461
 
                                    on_tm_dnd_get_uri_foreach, reply);
462
 
            break;
463
 
        case DND_TEXT_PLAIN:
464
 
            gtk_tree_selection_selected_foreach(ts,
465
 
                                    on_tm_dnd_get_file_foreach, reply);
466
 
            break;
467
 
        default:
468
 
            g_warning ("Programming error: tm_drag_data_get received unknown info type (%d)\n", info);
469
 
            break;
470
 
        }
471
 
    }
472
 
    gtk_selection_data_set(data, data->target, 8, reply->str, reply->len);
473
 
    g_string_free (reply, TRUE);
474
 
}
475
 
 
476
 
static void tm_drag_data_received (GtkWidget       *widget,
477
 
                                   GdkDragContext  *dc,
478
 
                                   gint             x,
479
 
                                   gint             y,
480
 
                                   GtkSelectionData *data,
481
 
                                   guint            info,
482
 
                                   guint            time,
483
 
                                   gpointer         user_data)
484
 
{
485
 
    GtkTreePath *path = NULL;
486
 
    GtkTreeModel *model = NULL;
487
 
    GtkTreeViewDropPosition pos = 0;
488
 
    gboolean result = FALSE;
489
 
 
490
 
    /* printf ("sm drop received info: %d\n", info); */
491
 
 
492
 
    /* sometimes we get empty dnd data, ignore */
493
 
    if(widgets_blocked || (!dc) ||
494
 
       (!data) || (data->length < 0)) return;
495
 
    /* yet another check, i think it's an 8 bit per byte check */
496
 
    if(data->format != 8) return;
497
 
 
498
 
    display_remove_autoscroll_row_timeout (widget);
499
 
 
500
 
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
501
 
    g_return_if_fail (model);
502
 
    if (!gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
503
 
                                            x, y, &path, &pos))
504
 
    {
505
 
        gint py;
506
 
        gdk_window_get_pointer (
507
 
            gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget)),
508
 
            NULL, &py, NULL);
509
 
        if (py < 5)
510
 
        {
511
 
            /* initialize with first displayed and drop before */
512
 
            GtkTreeIter iter;
513
 
            if (gtk_tree_model_get_iter_first (model, &iter))
514
 
            {
515
 
                path = gtk_tree_model_get_path (model, &iter);
516
 
                pos = GTK_TREE_VIEW_DROP_BEFORE;
517
 
            }
518
 
        }
519
 
        else
520
 
        {   /* initialize with last path if available and drop after */
521
 
            GtkTreeIter iter;
522
 
            if (gtk_tree_model_get_iter_first (model, &iter))
523
 
            {
524
 
                GtkTreeIter last_valid_iter;
525
 
                do
526
 
                {
527
 
                    last_valid_iter = iter;
528
 
                } while (gtk_tree_model_iter_next (model, &iter));
529
 
                path = gtk_tree_model_get_path (model, &last_valid_iter);
530
 
                pos = GTK_TREE_VIEW_DROP_AFTER;
531
 
            }
532
 
        }
533
 
    }
534
 
 
535
 
    if (path)
536
 
    {   /* map position onto BEFORE or AFTER */
537
 
        switch (pos)
538
 
        {
539
 
        case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
540
 
        case GTK_TREE_VIEW_DROP_AFTER:
541
 
            pos = GTK_TREE_VIEW_DROP_AFTER;
542
 
            break;
543
 
        case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
544
 
        case GTK_TREE_VIEW_DROP_BEFORE:
545
 
            pos = GTK_TREE_VIEW_DROP_BEFORE;
546
 
            break;
547
 
        }
548
 
    }
549
 
 
550
 
    switch (info)
551
 
    {
552
 
    case DND_GTKPOD_TM_PATHLIST:
553
 
        g_return_if_fail (path);
554
 
        result = tm_move_pathlist (data->data, path, pos);
555
 
        dc->action = GDK_ACTION_MOVE;
556
 
        gtk_drag_finish (dc, TRUE, FALSE, time);
557
 
        break;
558
 
    case DND_TEXT_PLAIN:
559
 
        result = tm_add_filelist (data->data, path, pos);
560
 
        dc->action = dc->suggested_action;
561
 
        if (dc->action == GDK_ACTION_MOVE)
562
 
            gtk_drag_finish (dc, TRUE, TRUE, time);
563
 
        else
564
 
            gtk_drag_finish (dc, TRUE, FALSE, time);
565
 
        break;
566
 
    case DND_TEXT_URI_LIST:
567
 
        result = tm_add_filelist (data->data, path, pos);
568
 
        dc->action = dc->suggested_action;
569
 
        if (dc->action == GDK_ACTION_MOVE)
570
 
            gtk_drag_finish (dc, TRUE, TRUE, time);
571
 
        else
572
 
            gtk_drag_finish (dc, TRUE, FALSE, time);
573
 
        break;
574
 
    default:
575
 
        dc->action = 0;
576
 
        gtk_drag_finish (dc, FALSE, FALSE, time);
577
 
/*      puts ("tm_drag_data_received(): should not be reached"); */
578
 
        break;
579
 
    }
580
 
    if (path) gtk_tree_path_free(path);
581
 
}
582
 
 
583
 
/* ---------------------------------------------------------------- */
584
 
/* Section for track display                                        */
585
 
/* other callbacks                                                  */
586
 
/* ---------------------------------------------------------------- */
587
 
 
588
 
static gboolean
589
 
on_track_treeview_key_release_event     (GtkWidget       *widget,
590
 
                                        GdkEventKey     *event,
591
 
                                        gpointer         user_data)
592
 
{
593
 
    guint mods;
594
 
    mods = event->state;
595
 
 
596
 
    if(!widgets_blocked && (mods & GDK_CONTROL_MASK))
597
 
    {
598
 
        switch(event->keyval)
599
 
        {
600
 
/*          case GDK_u: */
601
 
/*              gp_do_selected_tracks (update_tracks); */
602
 
/*              break; */
603
 
            default:
604
 
                break;
605
 
        }
606
 
    }
607
 
    return FALSE;
608
 
}
609
 
 
610
 
/* ---------------------------------------------------------------- */
611
 
/* Section for track display                                        */
612
 
/* ---------------------------------------------------------------- */
613
 
 
614
 
/* Append track to the track model (or write into @into_iter if != 0) */
615
 
void tm_add_track_to_track_model (Track *track, GtkTreeIter *into_iter)
616
 
{
617
 
    GtkTreeIter iter;
618
 
    GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
619
 
 
620
 
    g_return_if_fail (model != NULL);
621
 
 
622
 
    if (into_iter)
623
 
        iter = *into_iter;
624
 
    else
625
 
        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
626
 
 
627
 
    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
628
 
                        READOUT_COL, track, -1);
629
 
}
630
 
 
631
 
 
632
 
 
633
 
/* Used by remove_track() to remove track from model by calling
634
 
   gtk_tree_model_foreach ().
635
 
   Entry is deleted if data == track */
636
 
static gboolean tm_delete_track (GtkTreeModel *model,
637
 
                                GtkTreePath *path,
638
 
                                GtkTreeIter *iter,
639
 
                                gpointer data)
640
 
{
641
 
  Track *track;
642
 
 
643
 
  gtk_tree_model_get (model, iter, READOUT_COL, &track, -1);
644
 
  if(track == (Track *)data)
645
 
  {
646
 
      GtkTreeSelection *selection = gtk_tree_view_get_selection
647
 
          (track_treeview);
648
 
/*       printf("unselect...\n"); */
649
 
      gtk_tree_selection_unselect_iter (selection, iter);
650
 
/*       printf("...unselect done\n"); */
651
 
      gtk_list_store_remove (GTK_LIST_STORE (model), iter);
652
 
      return TRUE;
653
 
  }
654
 
  return FALSE;
655
 
}
656
 
 
657
 
 
658
 
/* Remove track from the display model */
659
 
void tm_remove_track (Track *track)
660
 
{
661
 
  GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
662
 
  if (model != NULL)
663
 
    gtk_tree_model_foreach (model, tm_delete_track, track);
664
 
}
665
 
 
666
 
 
667
 
/* Remove all tracks from the display model */
668
 
void tm_remove_all_tracks ()
669
 
{
670
 
  GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
671
 
  GtkTreeIter iter;
672
 
 
673
 
  while (gtk_tree_model_get_iter_first (model, &iter))
674
 
  {
675
 
      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
676
 
  }
677
 
  tm_store_col_order ();
678
 
  tm_update_default_sizes ();
679
 
}
680
 
 
681
 
/* find out at which position column @tm_item is displayed */
682
 
/* static gint tm_get_col_position (TM_item tm_item) */
683
 
/* { */
684
 
/*     gint i; */
685
 
/*     GtkTreeViewColumn *col; */
686
 
 
687
 
/*     if (!track_treeview) return -1; */
688
 
 
689
 
/*     for (i=0; i<TM_NUM_COLUMNS_PREFS; ++i) */
690
 
/*     { */
691
 
/*      col = gtk_tree_view_get_column (track_treeview, i); */
692
 
/*      if (col->sort_column_id == tm_item) return i; */
693
 
/*     } */
694
 
/*     return -1; */
695
 
/* } */
696
 
 
697
 
 
698
 
/* store the order of the track view columns */
699
 
void tm_store_col_order (void)
700
 
{
701
 
    gint i;
702
 
    GtkTreeViewColumn *col;
703
 
 
704
 
    for (i=0; i<TM_NUM_COLUMNS; ++i)
705
 
    {
706
 
        col = gtk_tree_view_get_column (track_treeview, i);
707
 
        prefs_set_int_index("col_order", i, col->sort_column_id);
708
 
    }
709
 
}
710
 
 
711
 
 
712
 
/* Used by tm_track_changed() to find the track that
713
 
   changed name. If found, emit a "row changed" signal */
714
 
static gboolean tm_model_track_changed (GtkTreeModel *model,
715
 
                                       GtkTreePath *path,
716
 
                                       GtkTreeIter *iter,
717
 
                                       gpointer data)
718
 
{
719
 
  Track *track;
720
 
 
721
 
  gtk_tree_model_get (model, iter, READOUT_COL, &track, -1);
722
 
  if(track == (Track *)data) {
723
 
    gtk_tree_model_row_changed (model, path, iter);
724
 
    return TRUE;
725
 
  }
726
 
  return FALSE;
727
 
}
728
 
 
729
 
 
730
 
/* One of the tracks has changed (this happens when the
731
 
   iTunesDB is read and some IDs are renumbered */
732
 
void tm_track_changed (Track *track)
733
 
{
734
 
  GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
735
 
  /*  printf("tm_track_changed enter\n");*/
736
 
  if (model != NULL)
737
 
    gtk_tree_model_foreach (model, tm_model_track_changed, track);
738
 
  /*  printf("tm_track_changed exit\n");*/
739
 
}
740
 
 
741
 
 
742
 
 
743
 
#if ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION < 2))
744
 
/* gtk_tree_selection_get_selected_rows() was introduced in 2.2 */
745
 
struct gtsgsr
746
 
{
747
 
    GtkTreeModel **model;
748
 
    GList        **list;
749
 
};
750
 
 
751
 
void  gtssf  (GtkTreeModel *model,
752
 
              GtkTreePath *path,
753
 
              GtkTreeIter *iter,
754
 
              gpointer data)
755
 
{
756
 
    struct gtsgsr *gts = data;
757
 
    *gts->model = model;
758
 
    *gts->list = g_list_append (*gts->list, gtk_tree_path_copy (path));
759
 
}
760
 
 
761
 
GList *gtk_tree_selection_get_selected_rows (GtkTreeSelection *selection,
762
 
                                             GtkTreeModel     **model)
763
 
{
764
 
    struct gtsgsr gts;
765
 
    GList *list = NULL;
766
 
 
767
 
    gts.model = model;
768
 
    gts.list = &list;
769
 
 
770
 
    gtk_tree_selection_selected_foreach (selection, gtssf, &gts);
771
 
    return list;
772
 
}
773
 
#endif
774
 
 
775
 
 
776
 
/* Called when editable cell is being edited. Stores new data to the
777
 
   track list. ID3 tags in the corresponding files are updated as
778
 
   well, if activated in the pref settings */
779
 
static void
780
 
tm_cell_edited (GtkCellRendererText *renderer,
781
 
                const gchar         *path_string,
782
 
                const gchar         *new_text,
783
 
                gpointer             data)
784
 
{
785
 
  GtkTreeModel *model;
786
 
  GtkTreeSelection *selection;
787
 
  TM_item column;
788
 
  gboolean multi_edit;
789
 
  gint sel_rows_num;
790
 
  GList *row_list, *row_node, *first;
791
 
 
792
 
 
793
 
  column = (TM_item) g_object_get_data(G_OBJECT(renderer), "column");
794
 
  multi_edit = prefs_get_int("multi_edit");
795
 
  if (column == TM_COLUMN_TITLE)
796
 
      multi_edit &= prefs_get_int("multi_edit_title");
797
 
  selection = gtk_tree_view_get_selection(track_treeview);
798
 
  row_list = gtk_tree_selection_get_selected_rows(selection, &model);
799
 
 
800
 
/*   printf("tm_cell_edited: column: %d\n", column); */
801
 
 
802
 
  sel_rows_num = g_list_length (row_list);
803
 
 
804
 
  /* block widgets and update display if multi-edit is active */
805
 
  if (multi_edit && (sel_rows_num > 1)) block_widgets ();
806
 
 
807
 
  first = g_list_first (row_list);
808
 
 
809
 
  for (row_node = first;
810
 
       row_node && (multi_edit || (row_node == first));
811
 
       row_node = g_list_next(row_node))
812
 
  {
813
 
     Track *track;
814
 
     ExtraTrackData *etr;
815
 
     gboolean changed;
816
 
     GtkTreeIter iter;
817
 
     gchar *str;
818
 
 
819
 
     gtk_tree_model_get_iter(model, &iter, (GtkTreePath *) row_node->data);
820
 
     gtk_tree_model_get(model, &iter, READOUT_COL, &track, -1);
821
 
     g_return_if_fail (track);
822
 
     etr = track->userdata;
823
 
     g_return_if_fail (etr);
824
 
 
825
 
 
826
 
     changed = FALSE;
827
 
 
828
 
     switch(column)
829
 
     {
830
 
     case TM_COLUMN_TITLE:
831
 
     case TM_COLUMN_ALBUM:
832
 
     case TM_COLUMN_ARTIST:
833
 
     case TM_COLUMN_GENRE:
834
 
     case TM_COLUMN_COMPOSER:
835
 
     case TM_COLUMN_COMMENT:
836
 
     case TM_COLUMN_FILETYPE:
837
 
     case TM_COLUMN_GROUPING:
838
 
     case TM_COLUMN_CATEGORY:
839
 
     case TM_COLUMN_DESCRIPTION:
840
 
     case TM_COLUMN_PODCASTURL:
841
 
     case TM_COLUMN_PODCASTRSS:
842
 
     case TM_COLUMN_SUBTITLE:
843
 
     case TM_COLUMN_TRACK_NR:
844
 
     case TM_COLUMN_TRACKLEN:
845
 
     case TM_COLUMN_CD_NR:
846
 
     case TM_COLUMN_YEAR:
847
 
     case TM_COLUMN_PLAYCOUNT:
848
 
     case TM_COLUMN_RATING:
849
 
     case TM_COLUMN_TIME_ADDED:
850
 
     case TM_COLUMN_TIME_PLAYED:
851
 
     case TM_COLUMN_TIME_MODIFIED:
852
 
     case TM_COLUMN_TIME_RELEASED:
853
 
     case TM_COLUMN_VOLUME:
854
 
     case TM_COLUMN_SOUNDCHECK:
855
 
     case TM_COLUMN_BITRATE:
856
 
     case TM_COLUMN_SAMPLERATE:
857
 
     case TM_COLUMN_BPM:
858
 
         changed = track_set_text (track, new_text, TM_to_T (column));
859
 
         if (changed && (column == TM_COLUMN_TRACKLEN))
860
 
         {  /* be on the safe side and reset starttime, stoptime and
861
 
             * filesize */
862
 
             gchar *path = get_file_name_from_source (track,
863
 
                                                      SOURCE_PREFER_LOCAL);
864
 
             track->starttime = 0;
865
 
             track->stoptime = 0;
866
 
             if (path)
867
 
             {
868
 
                 struct stat filestat;
869
 
                 stat (path, &filestat);
870
 
                 track->size = filestat.st_size;
871
 
             }
872
 
         }
873
 
         /* redisplay some items to be on the safe side */
874
 
         switch (column)
875
 
         {
876
 
         case TM_COLUMN_TRACK_NR:
877
 
         case TM_COLUMN_CD_NR:
878
 
         case TM_COLUMN_TRACKLEN:
879
 
         case TM_COLUMN_TIME_ADDED:
880
 
         case TM_COLUMN_TIME_PLAYED:
881
 
         case TM_COLUMN_TIME_MODIFIED:
882
 
         case TM_COLUMN_TIME_RELEASED:
883
 
             str = track_get_text (track, TM_to_T (column));
884
 
             g_object_set (G_OBJECT (renderer), "text", str, NULL);
885
 
             g_free (str);
886
 
             break;
887
 
         default:
888
 
             break;
889
 
         }
890
 
         break;
891
 
     default:
892
 
        g_warning ("Programming error: tm_cell_edited: unknown track cell (%d) edited\n", column);
893
 
        break;
894
 
     }
895
 
/*      printf ("  changed: %d\n", changed); */
896
 
     if (changed)
897
 
     {
898
 
        track->time_modified = itdb_time_get_mac_time ();
899
 
        pm_track_changed (track);    /* notify playlist model... */
900
 
        data_changed (track->itdb); /* indicate that data has changed */
901
 
 
902
 
        if (prefs_get_int("id3_write"))
903
 
        {
904
 
            /* T_item tag_id;*/
905
 
           /* should we update all ID3 tags or just the one
906
 
              changed? -- obsoleted in 0.71*/
907
 
/*           if (prefs_get_id3_writeall ()) tag_id = T_ALL;
908
 
             else                           tag_id = TM_to_T (column);*/
909
 
           write_tags_to_file (track);
910
 
           /* display possible duplicates that have been removed */
911
 
           gp_duplicate_remove (NULL, NULL);
912
 
        }
913
 
     }
914
 
     while (widgets_blocked && gtk_events_pending ())  gtk_main_iteration ();
915
 
  }
916
 
 
917
 
  if (multi_edit && (sel_rows_num > 1)) release_widgets ();
918
 
 
919
 
  g_list_foreach(row_list, (GFunc) gtk_tree_path_free, NULL);
920
 
  g_list_free(row_list);
921
 
}
922
 
 
923
 
 
924
 
/* The track data is stored in a separate list (static GList *tracks)
925
 
   and only pointers to the corresponding Track structure are placed
926
 
   into the model.
927
 
   This function reads the data for the given cell from the list and
928
 
   passes it to the renderer. */
929
 
static void tm_cell_data_func (GtkTreeViewColumn *tree_column,
930
 
                               GtkCellRenderer   *renderer,
931
 
                               GtkTreeModel      *model,
932
 
                               GtkTreeIter       *iter,
933
 
                               gpointer           data)
934
 
{
935
 
  Track *track;
936
 
  ExtraTrackData *etr;
937
 
  iTunesDB *itdb;
938
 
  TM_item column;
939
 
  gchar *text;
940
 
 
941
 
  column = (TM_item)g_object_get_data (G_OBJECT (renderer), "column");
942
 
 
943
 
  g_return_if_fail ((column >= 0) && (column < TM_NUM_COLUMNS));
944
 
 
945
 
  gtk_tree_model_get (model, iter, READOUT_COL, &track, -1);
946
 
  g_return_if_fail (track);
947
 
  etr = track->userdata;
948
 
  g_return_if_fail (etr);
949
 
  itdb = track->itdb;
950
 
  g_return_if_fail (itdb);
951
 
 
952
 
  text = track_get_text (track, TM_to_T (column));
953
 
 
954
 
  switch (column)
955
 
  {
956
 
  case TM_COLUMN_TITLE:
957
 
  case TM_COLUMN_ARTIST:
958
 
  case TM_COLUMN_ALBUM:
959
 
  case TM_COLUMN_GENRE:
960
 
  case TM_COLUMN_COMPOSER:
961
 
  case TM_COLUMN_COMMENT:
962
 
  case TM_COLUMN_FILETYPE:
963
 
  case TM_COLUMN_GROUPING:
964
 
  case TM_COLUMN_CATEGORY:
965
 
  case TM_COLUMN_DESCRIPTION:
966
 
  case TM_COLUMN_PODCASTURL:
967
 
  case TM_COLUMN_PODCASTRSS:
968
 
  case TM_COLUMN_SUBTITLE:
969
 
  case TM_COLUMN_TIME_PLAYED:
970
 
  case TM_COLUMN_TIME_MODIFIED:
971
 
  case TM_COLUMN_TIME_ADDED:
972
 
  case TM_COLUMN_TIME_RELEASED:
973
 
      g_object_set (G_OBJECT (renderer),
974
 
                    "text", text,
975
 
                    "editable", TRUE,
976
 
                    "xalign", 0.0, NULL);
977
 
      break;
978
 
  case TM_COLUMN_TRACK_NR:
979
 
  case TM_COLUMN_CD_NR:
980
 
  case TM_COLUMN_BITRATE:
981
 
  case TM_COLUMN_SAMPLERATE:
982
 
  case TM_COLUMN_BPM:
983
 
  case TM_COLUMN_PLAYCOUNT:
984
 
  case TM_COLUMN_YEAR:
985
 
  case TM_COLUMN_RATING:
986
 
  case TM_COLUMN_VOLUME:
987
 
  case TM_COLUMN_SOUNDCHECK:
988
 
  case TM_COLUMN_TRACKLEN:
989
 
      g_object_set (G_OBJECT (renderer),
990
 
                    "text", text,
991
 
                    "editable", TRUE,
992
 
                    "xalign", 1.0, NULL);
993
 
      break;
994
 
  case TM_COLUMN_IPOD_ID:
995
 
  case TM_COLUMN_SIZE:
996
 
      g_object_set (G_OBJECT (renderer),
997
 
                    "text", text,
998
 
                    "editable", FALSE,
999
 
                    "xalign", 1.0, NULL);
1000
 
      break;
1001
 
  case TM_COLUMN_PC_PATH:
1002
 
  case TM_COLUMN_IPOD_PATH:
1003
 
  case TM_COLUMN_THUMB_PATH:
1004
 
      g_object_set (G_OBJECT (renderer),
1005
 
                    "text", text,
1006
 
                    "editable", FALSE,
1007
 
                    "xalign", 0.0, NULL);
1008
 
      break;
1009
 
  case TM_COLUMN_TRANSFERRED:
1010
 
      g_object_set (G_OBJECT (renderer),
1011
 
                    "active", track->transferred,
1012
 
                    "activatable", FALSE, NULL);
1013
 
      break;
1014
 
  case TM_COLUMN_COMPILATION:
1015
 
      g_object_set (G_OBJECT (renderer),
1016
 
                    "active", track->compilation,
1017
 
                    "activatable", TRUE, NULL);
1018
 
      break;
1019
 
  case TM_NUM_COLUMNS:
1020
 
      break;
1021
 
  }
1022
 
  g_free (text);
1023
 
}
1024
 
 
1025
 
 
1026
 
 
1027
 
/* Called when a toggle cell is being changed. Stores new data to the
1028
 
   track list. */
1029
 
static void
1030
 
tm_cell_toggled (GtkCellRendererToggle *renderer,
1031
 
                 gchar *arg1,
1032
 
                 gpointer user_data)
1033
 
{
1034
 
  GtkTreeModel *model;
1035
 
  GtkTreeSelection *selection;
1036
 
  TM_item column;
1037
 
  gboolean multi_edit;
1038
 
  gint sel_rows_num;
1039
 
  GList *row_list, *row_node, *first;
1040
 
  gboolean active;
1041
 
 
1042
 
  column = (TM_item) g_object_get_data(G_OBJECT(renderer), "column");
1043
 
  multi_edit = prefs_get_int("multi_edit");
1044
 
  selection = gtk_tree_view_get_selection(track_treeview);
1045
 
  row_list = gtk_tree_selection_get_selected_rows(selection, &model);
1046
 
 
1047
 
/*  printf("tm_cell_toggled: column: %d, arg1: %p\n", column, arg1); */
1048
 
 
1049
 
  sel_rows_num = g_list_length (row_list);
1050
 
 
1051
 
  /* block widgets and update display if multi-edit is active */
1052
 
  if (multi_edit && (sel_rows_num > 1)) block_widgets ();
1053
 
 
1054
 
  first = g_list_first (row_list);
1055
 
 
1056
 
  /* active will show the old state -- before the toggle */
1057
 
  g_object_get (G_OBJECT (renderer), "active", &active, NULL);
1058
 
 
1059
 
  for (row_node = first;
1060
 
       row_node && (multi_edit || (row_node == first));
1061
 
       row_node = g_list_next(row_node))
1062
 
  {
1063
 
     Track *track;
1064
 
     gboolean changed;
1065
 
     GtkTreeIter iter;
1066
 
 
1067
 
     gtk_tree_model_get_iter(model, &iter, (GtkTreePath *) row_node->data);
1068
 
     gtk_tree_model_get(model, &iter, READOUT_COL, &track, -1);
1069
 
     changed = FALSE;
1070
 
 
1071
 
     switch(column)
1072
 
     {
1073
 
     case TM_COLUMN_TITLE:
1074
 
         if ((active && (track->checked == 0)) ||
1075
 
             (!active && (track->checked == 1)))
1076
 
             changed = TRUE;
1077
 
         if (active) track->checked = 1;
1078
 
         else        track->checked = 0;
1079
 
         break;
1080
 
     case TM_COLUMN_COMPILATION:
1081
 
         if ((!active && (track->compilation == 0)) ||
1082
 
             (active && (track->compilation == 1)))
1083
 
             changed = TRUE;
1084
 
         if (!active) track->compilation = 1;
1085
 
         else        track->compilation = 0;
1086
 
        break;
1087
 
     default:
1088
 
        g_warning ("Programming error: tm_cell_toggled: unknown track cell (%d) edited\n", column);
1089
 
        break;
1090
 
     }
1091
 
/*      printf ("  changed: %d\n", changed); */
1092
 
     if (changed)
1093
 
     {
1094
 
        track->time_modified = itdb_time_get_mac_time ();
1095
 
/*        pm_track_changed (track);  notify playlist model... -- not
1096
 
 *        necessary here because only the track model is affected */
1097
 
        data_changed (track->itdb);  /* indicate that data has changed */
1098
 
        
1099
 
        /* If the changed column is the compilation flag update the file
1100
 
           if required */
1101
 
        if (column == TM_COLUMN_COMPILATION)
1102
 
           if (prefs_get_int("id3_write"))
1103
 
              write_tags_to_file (track);
1104
 
        
1105
 
     }
1106
 
     while (widgets_blocked && gtk_events_pending ())  gtk_main_iteration ();
1107
 
  }
1108
 
 
1109
 
  if (multi_edit && (sel_rows_num > 1)) release_widgets ();
1110
 
 
1111
 
  g_list_foreach(row_list, (GFunc) gtk_tree_path_free, NULL);
1112
 
  g_list_free(row_list);
1113
 
}
1114
 
 
1115
 
 
1116
 
 
1117
 
/* The track data is stored in a separate list (static GList *tracks)
1118
 
   and only pointers to the corresponding Track structure are placed
1119
 
   into the model.
1120
 
   This function reads the data for the given cell from the list and
1121
 
   passes it to the renderer. */
1122
 
static void tm_cell_data_func_toggle (GtkTreeViewColumn *tree_column,
1123
 
                                      GtkCellRenderer   *renderer,
1124
 
                                      GtkTreeModel      *model,
1125
 
                                      GtkTreeIter       *iter,
1126
 
                                      gpointer           data)
1127
 
{
1128
 
  Track *track;
1129
 
  TM_item column;
1130
 
 
1131
 
  column = (TM_item)g_object_get_data (G_OBJECT (renderer), "column");
1132
 
  gtk_tree_model_get (model, iter, READOUT_COL, &track, -1);
1133
 
 
1134
 
  switch (column)
1135
 
  {
1136
 
  case TM_COLUMN_TITLE:
1137
 
      g_object_set (G_OBJECT (renderer),
1138
 
                    "active", !track->checked,
1139
 
                    "activatable", TRUE, NULL);
1140
 
      break;
1141
 
  default:
1142
 
      g_warning ("Programming error: unknown column in tm_cell_data_func_toggle: %d\n", column);
1143
 
      break;
1144
 
  }
1145
 
}
1146
 
 
1147
 
/**
1148
 
 * tm_get_nr_of_tracks - get the number of tracks displayed
1149
 
 * currently in the track model Returns - the number of tracks displayed
1150
 
 * currently
1151
 
 */
1152
 
guint
1153
 
tm_get_nr_of_tracks(void)
1154
 
{
1155
 
    GtkTreeIter i;
1156
 
    guint result = 0;
1157
 
    gboolean valid = FALSE;
1158
 
    GtkTreeModel *tm = NULL;
1159
 
 
1160
 
    if((tm = gtk_tree_view_get_model(GTK_TREE_VIEW(track_treeview))))
1161
 
    {
1162
 
        if((valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tm),&i)))
1163
 
        {
1164
 
            result++;
1165
 
            while((valid = gtk_tree_model_iter_next(tm,&i)))
1166
 
                result++;
1167
 
        }
1168
 
    }
1169
 
    return(result);
1170
 
 
1171
 
}
1172
 
 
1173
 
 
1174
 
static gint comp_int (gconstpointer a, gconstpointer b)
1175
 
{
1176
 
    return (GPOINTER_TO_INT(a)-(GPOINTER_TO_INT(b)));
1177
 
}
1178
 
 
1179
 
 
1180
 
/**
1181
 
 * Reorder tracks in playlist to match order of tracks displayed in track
1182
 
 * view. Only the subset of tracks currently displayed is reordered.
1183
 
 * data_changed() is called when necessary.
1184
 
 */
1185
 
void
1186
 
tm_rows_reordered (void)
1187
 
{
1188
 
    Playlist *current_pl;
1189
 
 
1190
 
    g_return_if_fail (track_treeview);
1191
 
    current_pl = pm_get_selected_playlist ();
1192
 
 
1193
 
    if(current_pl)
1194
 
    {
1195
 
        GtkTreeModel *tm = NULL;
1196
 
        GtkTreeIter i;
1197
 
        GList *new_list = NULL, *old_pos_l = NULL;
1198
 
        gboolean valid = FALSE;
1199
 
        GList *nlp, *olp;
1200
 
        gboolean changed = FALSE;
1201
 
        iTunesDB *itdb = NULL;
1202
 
 
1203
 
        tm = gtk_tree_view_get_model (track_treeview);
1204
 
        g_return_if_fail (tm);
1205
 
 
1206
 
        valid = gtk_tree_model_get_iter_first (tm,&i);
1207
 
        while (valid)
1208
 
        {
1209
 
            Track *new_track;
1210
 
            gint old_position;
1211
 
 
1212
 
            gtk_tree_model_get (tm, &i, READOUT_COL, &new_track, -1);
1213
 
            g_return_if_fail (new_track);
1214
 
 
1215
 
            if (!itdb) itdb = new_track->itdb;
1216
 
            new_list = g_list_append (new_list, new_track);
1217
 
            /* what position was this track in before? */
1218
 
            old_position = g_list_index (current_pl->members, new_track);
1219
 
            /* check if we already used this position before (can
1220
 
               happen if track has been added to playlist more than
1221
 
               once */
1222
 
            while ((old_position != -1) &&
1223
 
                   g_list_find (old_pos_l, GINT_TO_POINTER(old_position)))
1224
 
            {  /* find next occurence */
1225
 
                GList *link;
1226
 
                gint next;
1227
 
                link = g_list_nth (current_pl->members, old_position + 1);
1228
 
                next = g_list_index (link, new_track);
1229
 
                if (next == -1)   old_position = -1;
1230
 
                else              old_position += (1+next);
1231
 
            }
1232
 
            /* we make a sorted list of the old positions */
1233
 
            old_pos_l = g_list_insert_sorted (old_pos_l,
1234
 
                                              GINT_TO_POINTER(old_position),
1235
 
                                              comp_int);
1236
 
            valid = gtk_tree_model_iter_next (tm, &i);
1237
 
        }
1238
 
        nlp = new_list;
1239
 
        olp = old_pos_l;
1240
 
        while (nlp && olp)
1241
 
        {
1242
 
            GList *old_link;
1243
 
            guint position = GPOINTER_TO_INT(olp->data);
1244
 
 
1245
 
            /* if position == -1 one of the tracks in the track view
1246
 
               could not be found in the selected playlist -> stop! */
1247
 
            if (position == -1)
1248
 
            {
1249
 
                g_warning ("Programming error: tm_rows_reordered_callback: track in track view was not in selected playlist\n");
1250
 
                g_return_if_reached ();
1251
 
            }
1252
 
            old_link = g_list_nth (current_pl->members, position);
1253
 
            /* replace old track with new track */
1254
 
            if (old_link->data != nlp->data)
1255
 
            {
1256
 
                old_link->data = nlp->data;
1257
 
                changed = TRUE;
1258
 
            }
1259
 
            /* next */
1260
 
            nlp = nlp->next;
1261
 
            olp = olp->next;
1262
 
        }
1263
 
        g_list_free (new_list);
1264
 
        g_list_free (old_pos_l);
1265
 
        /* if we changed data, mark data as changed and adopt order in
1266
 
           sort tabs */
1267
 
        if (changed)
1268
 
        {
1269
 
            data_changed (itdb);
1270
 
            st_adopt_order_in_playlist ();
1271
 
        }
1272
 
    }
1273
 
}
1274
 
 
1275
 
 
1276
 
static void
1277
 
on_trackids_list_foreach ( GtkTreeModel *tm, GtkTreePath *tp,
1278
 
                           GtkTreeIter *i, gpointer data)
1279
 
{
1280
 
    Track *tr = NULL;
1281
 
    GList *l = *((GList**)data);
1282
 
    gtk_tree_model_get(tm, i, READOUT_COL, &tr, -1);
1283
 
    g_return_if_fail (tr);
1284
 
    l = g_list_append(l, GUINT_TO_POINTER(tr->id));
1285
 
    *((GList**)data) = l;
1286
 
}
1287
 
 
1288
 
 
1289
 
/* return a list containing the track IDs of all tracks currently being
1290
 
   selected */
1291
 
GList *
1292
 
tm_get_selected_trackids(void)
1293
 
{
1294
 
    GList *result = NULL;
1295
 
    GtkTreeSelection *ts = NULL;
1296
 
 
1297
 
    if((ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(track_treeview))))
1298
 
    {
1299
 
        gtk_tree_selection_selected_foreach(ts, on_trackids_list_foreach,
1300
 
                                            &result);
1301
 
    }
1302
 
    return(result);
1303
 
}
1304
 
 
1305
 
/* return a list containing the track IDs of all tracks currently being
1306
 
   displayed */
1307
 
GList *
1308
 
tm_get_all_trackids(void)
1309
 
{
1310
 
    gboolean
1311
 
        on_all_trackids_list_foreach (GtkTreeModel *tm, GtkTreePath *tp,
1312
 
                                      GtkTreeIter *i, gpointer data)
1313
 
        {
1314
 
            on_trackids_list_foreach (tm, tp, i, data);
1315
 
            return FALSE;
1316
 
        }
1317
 
    GList *result = NULL;
1318
 
    GtkTreeModel *model;
1319
 
 
1320
 
    if((model = gtk_tree_view_get_model (track_treeview)))
1321
 
    {
1322
 
        gtk_tree_model_foreach(model, on_all_trackids_list_foreach,
1323
 
                               &result);
1324
 
    }
1325
 
    return(result);
1326
 
}
1327
 
 
1328
 
static void
1329
 
on_tracks_list_foreach ( GtkTreeModel *tm, GtkTreePath *tp,
1330
 
                         GtkTreeIter *i, gpointer data)
1331
 
{
1332
 
    Track *tr = NULL;
1333
 
    GList *l = *((GList**)data);
1334
 
    gtk_tree_model_get(tm, i, READOUT_COL, &tr, -1);
1335
 
    g_return_if_fail (tr);
1336
 
    l = g_list_append(l, tr);
1337
 
    *((GList**)data) = l;
1338
 
}
1339
 
 
1340
 
 
1341
 
/* return a list containing pointers to all tracks currently being
1342
 
   selected */
1343
 
GList *
1344
 
tm_get_selected_tracks(void)
1345
 
{
1346
 
    GList *result = NULL;
1347
 
    GtkTreeSelection *ts = NULL;
1348
 
 
1349
 
    if((ts = gtk_tree_view_get_selection(GTK_TREE_VIEW(track_treeview))))
1350
 
    {
1351
 
        gtk_tree_selection_selected_foreach(ts, on_tracks_list_foreach,
1352
 
                                            &result);
1353
 
    }
1354
 
    return(result);
1355
 
}
1356
 
 
1357
 
 
1358
 
 
1359
 
    /* used by tm_get_all_tracks */
1360
 
    static gboolean on_all_tracks_list_foreach (GtkTreeModel *tm,
1361
 
                                                GtkTreePath *tp,
1362
 
                                                GtkTreeIter *i,
1363
 
                                                gpointer data)
1364
 
    {
1365
 
        on_tracks_list_foreach (tm, tp, i, data);
1366
 
        return FALSE;
1367
 
    }
1368
 
 
1369
 
 
1370
 
/* return a list containing pointers to all tracks currently being
1371
 
   displayed. You must g_list_free() the list after use. */
1372
 
GList *
1373
 
tm_get_all_tracks(void)
1374
 
{
1375
 
    GList *result = NULL;
1376
 
    GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
1377
 
 
1378
 
    g_return_val_if_fail (model, NULL);
1379
 
 
1380
 
    gtk_tree_model_foreach(model, on_all_tracks_list_foreach,
1381
 
                           &result);
1382
 
    return result;
1383
 
}
1384
 
 
1385
 
 
1386
 
/* Stop editing. If @cancel is TRUE, the edited value will be
1387
 
   discarded (I have the feeling that the "discarding" part does not
1388
 
   work quite the way intended). */
1389
 
void tm_stop_editing (gboolean cancel)
1390
 
{
1391
 
    GtkTreeViewColumn *col;
1392
 
 
1393
 
    if (!track_treeview)  return;
1394
 
 
1395
 
    gtk_tree_view_get_cursor (track_treeview, NULL, &col);
1396
 
    if (col)
1397
 
    {
1398
 
        /* Before removing the widget we set multi_edit to FALSE. That
1399
 
           way at most one entry will be changed (this also doesn't
1400
 
           seem to work the way intended) */
1401
 
        gboolean me = prefs_get_int("multi_edit");
1402
 
        prefs_set_int("multi_edit", FALSE);
1403
 
        if (!cancel && col->editable_widget)
1404
 
            gtk_cell_editable_editing_done (col->editable_widget);
1405
 
        if (col->editable_widget)
1406
 
            gtk_cell_editable_remove_widget (col->editable_widget);
1407
 
        prefs_set_int("multi_edit", me);
1408
 
    }
1409
 
}
1410
 
 
1411
 
 
1412
 
 
1413
 
/* Function to compare @tm_item of @track1 and @track2. Used by
1414
 
   tm_data_compare_func() */
1415
 
static gint tm_data_compare (Track *track1, Track *track2,
1416
 
                             TM_item tm_item)
1417
 
{
1418
 
  gint cmp = 0;
1419
 
  ExtraTrackData *etr1, *etr2;
1420
 
 
1421
 
 
1422
 
  g_return_val_if_fail (track1 && track2, 0);
1423
 
 
1424
 
  switch (tm_item)
1425
 
  {
1426
 
  case TM_COLUMN_TITLE:
1427
 
  case TM_COLUMN_ALBUM:
1428
 
  case TM_COLUMN_GENRE:
1429
 
  case TM_COLUMN_COMPOSER:
1430
 
  case TM_COLUMN_COMMENT:
1431
 
  case TM_COLUMN_FILETYPE:
1432
 
  case TM_COLUMN_GROUPING:
1433
 
  case TM_COLUMN_ARTIST:
1434
 
  case TM_COLUMN_CATEGORY:
1435
 
  case TM_COLUMN_DESCRIPTION:
1436
 
  case TM_COLUMN_PODCASTURL:
1437
 
  case TM_COLUMN_PODCASTRSS:
1438
 
  case TM_COLUMN_SUBTITLE:
1439
 
      /* string_compare_func is set to either compare_string_fuzzy or
1440
 
         compare_string in tm_sort_column_changed() which is called
1441
 
         once before the comparing begins. */
1442
 
      cmp = string_compare_func (
1443
 
          track_get_item (track1, TM_to_T (tm_item)),
1444
 
          track_get_item (track2, TM_to_T (tm_item)));
1445
 
      break;
1446
 
  case TM_COLUMN_TRACK_NR:
1447
 
      cmp = track1->tracks - track2->tracks;
1448
 
      if (cmp == 0) cmp = track1->track_nr - track2->track_nr;
1449
 
      break;
1450
 
  case TM_COLUMN_CD_NR:
1451
 
      cmp = track1->cds - track2->cds;
1452
 
      if (cmp == 0) cmp = track1->cd_nr - track2->cd_nr;
1453
 
      break;
1454
 
  case TM_COLUMN_IPOD_ID:
1455
 
      cmp = track1->id - track2->id;
1456
 
      break;
1457
 
  case TM_COLUMN_PC_PATH:
1458
 
      etr1 = track1->userdata;
1459
 
      etr2 = track2->userdata;
1460
 
      g_return_val_if_fail (etr1 && etr2, 0);
1461
 
      cmp = g_utf8_collate (etr1->pc_path_utf8, etr2->pc_path_utf8);
1462
 
      break;
1463
 
  case TM_COLUMN_IPOD_PATH:
1464
 
      cmp = g_utf8_collate (track1->ipod_path, track2->ipod_path);
1465
 
      break;
1466
 
  case TM_COLUMN_THUMB_PATH:
1467
 
      etr1 = track1->userdata;
1468
 
      etr2 = track2->userdata;
1469
 
      g_return_val_if_fail (etr1 && etr2, 0);
1470
 
      cmp = g_utf8_collate (etr1->thumb_path_utf8, etr2->thumb_path_utf8);
1471
 
      break;
1472
 
  case TM_COLUMN_TRANSFERRED:
1473
 
      if(track1->transferred == track2->transferred)
1474
 
          cmp = 0;
1475
 
      else if(track1->transferred == TRUE)
1476
 
          cmp = 1;
1477
 
      else
1478
 
          cmp = -1;
1479
 
      break;
1480
 
  case TM_COLUMN_COMPILATION:
1481
 
      if(track1->compilation == track2->compilation)
1482
 
          cmp = 0;
1483
 
      else if(track1->compilation == TRUE)
1484
 
          cmp = 1;
1485
 
      else
1486
 
          cmp = -1;
1487
 
      break;
1488
 
  case TM_COLUMN_SIZE:
1489
 
      cmp = track1->size - track2->size;
1490
 
      break;
1491
 
  case TM_COLUMN_TRACKLEN:
1492
 
      cmp = track1->tracklen - track2->tracklen;
1493
 
      break;
1494
 
  case TM_COLUMN_BITRATE:
1495
 
      cmp = track1->bitrate - track2->bitrate;
1496
 
      break;
1497
 
  case TM_COLUMN_SAMPLERATE:
1498
 
      cmp = track1->samplerate - track2->samplerate;
1499
 
      break;
1500
 
  case TM_COLUMN_BPM:
1501
 
      cmp = track1->BPM - track2->BPM;
1502
 
      break;
1503
 
  case TM_COLUMN_PLAYCOUNT:
1504
 
      cmp = track1->playcount - track2->playcount;
1505
 
      break;
1506
 
  case  TM_COLUMN_RATING:
1507
 
      cmp = track1->rating - track2->rating;
1508
 
      break;
1509
 
  case TM_COLUMN_TIME_ADDED:
1510
 
  case TM_COLUMN_TIME_PLAYED:
1511
 
  case TM_COLUMN_TIME_MODIFIED:
1512
 
  case TM_COLUMN_TIME_RELEASED:
1513
 
      cmp = COMP (time_get_time (track1, TM_to_T (tm_item)),
1514
 
                  time_get_time (track2, TM_to_T (tm_item)));
1515
 
      break;
1516
 
  case  TM_COLUMN_VOLUME:
1517
 
      cmp = track1->volume - track2->volume;
1518
 
      break;
1519
 
  case  TM_COLUMN_SOUNDCHECK:
1520
 
      /* If soundcheck is unset (0) use 0 dB (1000) */
1521
 
      cmp = (track1->soundcheck? track1->soundcheck:1000) - 
1522
 
          (track2->soundcheck? track2->soundcheck:1000);
1523
 
      break;
1524
 
  case TM_COLUMN_YEAR:
1525
 
      cmp = track1->year - track2->year;
1526
 
      break;
1527
 
  default:
1528
 
      g_warning ("Programming error: tm_data_compare_func: no sort method for tm_item %d\n", tm_item);
1529
 
      break;
1530
 
  }
1531
 
 
1532
 
  /* implement stable sorting: if two items are the same, revert to
1533
 
     the last relative positition */
1534
 
  if (cmp == 0)
1535
 
  {
1536
 
      etr1 = track1->userdata;
1537
 
      etr2 = track2->userdata;
1538
 
      g_return_val_if_fail (etr1 && etr2, 0);
1539
 
      cmp = etr1->sortindex - etr2->sortindex;
1540
 
  }
1541
 
  return cmp;
1542
 
}
1543
 
 
1544
 
 
1545
 
/* Function used to compare rows with user's search string */
1546
 
gboolean tm_search_equal_func (GtkTreeModel *model,
1547
 
                               gint column,
1548
 
                               const gchar *key,
1549
 
                               GtkTreeIter *iter,
1550
 
                               gpointer search_data)
1551
 
{
1552
 
  Track *track1;
1553
 
  gboolean cmp = 0;
1554
 
  gtk_tree_model_get (model, iter, READOUT_COL, &track1, -1);
1555
 
  switch (column)
1556
 
  {
1557
 
  case TM_COLUMN_TITLE:
1558
 
  case TM_COLUMN_ALBUM:
1559
 
  case TM_COLUMN_GENRE:
1560
 
  case TM_COLUMN_COMPOSER:
1561
 
  case TM_COLUMN_COMMENT:
1562
 
  case TM_COLUMN_FILETYPE:
1563
 
  case TM_COLUMN_GROUPING:
1564
 
  case TM_COLUMN_ARTIST:
1565
 
  case TM_COLUMN_CATEGORY:
1566
 
  case TM_COLUMN_DESCRIPTION:
1567
 
  case TM_COLUMN_PODCASTURL:
1568
 
  case TM_COLUMN_PODCASTRSS:
1569
 
  case TM_COLUMN_SUBTITLE:
1570
 
  case TM_COLUMN_PC_PATH:
1571
 
  case TM_COLUMN_YEAR:
1572
 
  case TM_COLUMN_IPOD_PATH:
1573
 
  case TM_COLUMN_COMPILATION:
1574
 
  case TM_COLUMN_THUMB_PATH:
1575
 
    cmp = (compare_string_start_case_insensitive (
1576
 
          track_get_item (track1, TM_to_T (column)),
1577
 
          key) != 0);
1578
 
    break;
1579
 
  case TM_COLUMN_TRACK_NR:
1580
 
  case TM_COLUMN_IPOD_ID:
1581
 
  case TM_COLUMN_TRANSFERRED:
1582
 
  case TM_COLUMN_SIZE:
1583
 
  case TM_COLUMN_TRACKLEN:
1584
 
  case TM_COLUMN_BITRATE:
1585
 
  case TM_COLUMN_PLAYCOUNT:
1586
 
  case TM_COLUMN_RATING:
1587
 
  case TM_COLUMN_TIME_PLAYED:
1588
 
  case TM_COLUMN_TIME_MODIFIED:
1589
 
  case TM_COLUMN_VOLUME:
1590
 
  case TM_COLUMN_CD_NR:
1591
 
  case TM_COLUMN_TIME_ADDED:
1592
 
  case TM_COLUMN_SOUNDCHECK:
1593
 
  case TM_COLUMN_SAMPLERATE:
1594
 
  case TM_COLUMN_BPM:
1595
 
  case TM_COLUMN_TIME_RELEASED:
1596
 
  case TM_NUM_COLUMNS:
1597
 
      g_warning ("Programming error: tm_search_equal_func: no sort method for column %d\n", column);
1598
 
      break;
1599
 
  }
1600
 
  return cmp;
1601
 
};
1602
 
 
1603
 
/* Function used to compare two cells during sorting (track view) */
1604
 
gint tm_data_compare_func (GtkTreeModel *model,
1605
 
                        GtkTreeIter *a,
1606
 
                        GtkTreeIter *b,
1607
 
                        gpointer user_data)
1608
 
{
1609
 
  Track *track1;
1610
 
  Track *track2;
1611
 
  gint column;
1612
 
  GtkSortType order;
1613
 
  gint result;
1614
 
 
1615
 
  gtk_tree_model_get (model, a, READOUT_COL, &track1, -1);
1616
 
  gtk_tree_model_get (model, b, READOUT_COL, &track2, -1);
1617
 
  if(gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1618
 
                                           &column, &order) == FALSE)
1619
 
      return 0;
1620
 
 
1621
 
  result = tm_data_compare (track1, track2, column);
1622
 
  return result;
1623
 
}
1624
 
 
1625
 
 
1626
 
/* set/read the counter used to remember how often the sort column has
1627
 
   been clicked.
1628
 
   @inc: negative: reset counter to 0
1629
 
   @inc: positive or zero : add to counter
1630
 
   return value: new value of the counter */
1631
 
gint tm_sort_counter (gint inc)
1632
 
{
1633
 
    static gint cnt = 0;
1634
 
 
1635
 
    if (inc <0)
1636
 
    {
1637
 
        cnt = 0;
1638
 
    }
1639
 
    else
1640
 
    {
1641
 
        cnt += inc;
1642
 
    }   
1643
 
    return cnt;
1644
 
}
1645
 
 
1646
 
 
1647
 
/* Redisplays the tracks in the track view according to the order
1648
 
 * stored in the sort tab view. This only works if the track view is
1649
 
 * not sorted --> skip if sorted */
1650
 
 
1651
 
void tm_adopt_order_in_sorttab (void)
1652
 
{
1653
 
    if (prefs_get_int("tm_sort_") == SORT_NONE)
1654
 
    {
1655
 
        GList *gl, *tracks = NULL;
1656
 
 
1657
 
        /* retrieve the currently displayed tracks (non ordered) from
1658
 
           the last sort tab or from the selected playlist if no sort
1659
 
           tabs are being used */
1660
 
        tm_remove_all_tracks ();
1661
 
        tracks = display_get_selected_members (prefs_get_int("sort_tab_num")-1);
1662
 
        for (gl=tracks; gl; gl=gl->next)
1663
 
            tm_add_track_to_track_model ((Track *)gl->data, NULL);
1664
 
    }
1665
 
}
1666
 
 
1667
 
 
1668
 
/* redisplay the contents of the track view in it's unsorted order */
1669
 
static void tm_unsort (void)
1670
 
{
1671
 
    if (track_treeview)
1672
 
    {
1673
 
        GtkTreeModel *model= gtk_tree_view_get_model (track_treeview);
1674
 
 
1675
 
        prefs_set_int("tm_sort_", SORT_NONE);
1676
 
        if (!BROKEN_GTK_TREE_SORT)
1677
 
        {
1678
 
/* no need to comment this out -- searching still works, but for lack
1679
 
   of a ctrl-g only the first occurence will be found */
1680
 
/*          gtk_tree_view_set_enable_search (GTK_TREE_VIEW
1681
 
 * (track_treeview), FALSE);*/ 
1682
 
            gtk_tree_sortable_set_sort_column_id
1683
 
                (GTK_TREE_SORTABLE (model),
1684
 
                 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1685
 
                 GTK_SORT_ASCENDING);
1686
 
            tm_adopt_order_in_sorttab ();
1687
 
        }
1688
 
        else
1689
 
        {
1690
 
            gtkpod_warning (_("Cannot unsort track view because of a bug in the GTK lib you are using (%d.%d.%d < 2.5.4). Once you sort the track view, you cannot go back to the unsorted state.\n\n"), gtk_major_version, gtk_minor_version, gtk_micro_version);
1691
 
        }
1692
 
        tm_sort_counter (-1);
1693
 
    }
1694
 
}
1695
 
 
1696
 
 
1697
 
static void tm_set_search_column (gint newcol)
1698
 
{
1699
 
/*     printf ("track_treeview: %p, col: %d\n", track_treeview, newcol); */
1700
 
    g_return_if_fail (track_treeview);
1701
 
 
1702
 
    gtk_tree_view_set_search_column (GTK_TREE_VIEW (track_treeview),
1703
 
                                       newcol);
1704
 
    switch (newcol)
1705
 
    {
1706
 
    case TM_COLUMN_TITLE:
1707
 
    case TM_COLUMN_ALBUM:
1708
 
    case TM_COLUMN_GENRE:
1709
 
    case TM_COLUMN_COMPOSER:
1710
 
    case TM_COLUMN_COMMENT:
1711
 
    case TM_COLUMN_FILETYPE:
1712
 
    case TM_COLUMN_GROUPING:
1713
 
    case TM_COLUMN_ARTIST:
1714
 
    case TM_COLUMN_CATEGORY:
1715
 
    case TM_COLUMN_DESCRIPTION:
1716
 
    case TM_COLUMN_PODCASTURL:
1717
 
    case TM_COLUMN_PODCASTRSS:
1718
 
    case TM_COLUMN_SUBTITLE:
1719
 
    case TM_COLUMN_PC_PATH:
1720
 
    case TM_COLUMN_YEAR:
1721
 
    case TM_COLUMN_IPOD_PATH:
1722
 
    case TM_COLUMN_COMPILATION:
1723
 
    case TM_COLUMN_THUMB_PATH:
1724
 
        gtk_tree_view_set_enable_search (GTK_TREE_VIEW (track_treeview), TRUE);
1725
 
        break;
1726
 
    case TM_COLUMN_TRACK_NR:
1727
 
    case TM_COLUMN_IPOD_ID:
1728
 
    case TM_COLUMN_TRANSFERRED:
1729
 
    case TM_COLUMN_SIZE:
1730
 
    case TM_COLUMN_TRACKLEN:
1731
 
    case TM_COLUMN_BITRATE:
1732
 
    case TM_COLUMN_PLAYCOUNT:
1733
 
    case TM_COLUMN_RATING:
1734
 
    case TM_COLUMN_TIME_PLAYED:
1735
 
    case TM_COLUMN_TIME_MODIFIED:
1736
 
    case TM_COLUMN_VOLUME:
1737
 
    case TM_COLUMN_CD_NR:
1738
 
    case TM_COLUMN_TIME_ADDED:
1739
 
    case TM_COLUMN_SOUNDCHECK:
1740
 
    case TM_COLUMN_SAMPLERATE:
1741
 
    case TM_COLUMN_BPM:
1742
 
    case TM_COLUMN_TIME_RELEASED:
1743
 
    case TM_NUM_COLUMNS:
1744
 
        gtk_tree_view_set_enable_search (GTK_TREE_VIEW (track_treeview), FALSE);
1745
 
        break;
1746
 
    }
1747
 
    prefs_set_int (TM_PREFS_SEARCH_COLUMN, newcol);
1748
 
}
1749
 
 
1750
 
 
1751
 
/* This is called before when changing the sort order or the sort
1752
 
   column, and before doing the sorting */
1753
 
static void tm_sort_column_changed (GtkTreeSortable *ts,
1754
 
                                    gpointer user_data)
1755
 
{
1756
 
    static gint lastcol = -1; /* which column was sorted last time? */
1757
 
    gchar *buf;
1758
 
    gint newcol;
1759
 
    GtkSortType order;
1760
 
    GList *tracks, *gl;
1761
 
    gint32 i, inc;
1762
 
 
1763
 
    gtk_tree_sortable_get_sort_column_id (ts, &newcol, &order);
1764
 
 
1765
 
/*     printf ("scc -- col: %d, order: %d\n", newcol, order);  */
1766
 
 
1767
 
    /* set compare function for strings (to speed up sorting) */
1768
 
    buf = g_strdup_printf ("sort_ign_field_%d", TM_to_T (newcol));
1769
 
    if (prefs_get_int (buf))
1770
 
        string_compare_func = compare_string_fuzzy;
1771
 
    else
1772
 
        string_compare_func = compare_string;
1773
 
    g_free (buf);
1774
 
 
1775
 
    /* don't do anything if no sort column is set */
1776
 
    if (newcol == -2)
1777
 
    {
1778
 
        lastcol = newcol;
1779
 
        return;
1780
 
    }
1781
 
 
1782
 
    if (newcol != lastcol)
1783
 
    {
1784
 
        tm_sort_counter (-1);
1785
 
        lastcol = newcol;
1786
 
    }
1787
 
 
1788
 
    if (tm_sort_counter (1) >= 3)
1789
 
    { /* after clicking three times, reset sort order! */
1790
 
        tm_unsort ();  /* also resets sort counter */
1791
 
    }
1792
 
    else
1793
 
    {
1794
 
        prefs_set_int("tm_sort_", order);
1795
 
    }
1796
 
    prefs_set_int("tm_sortcol", newcol);
1797
 
 
1798
 
    tm_set_search_column (newcol);
1799
 
 
1800
 
    if(prefs_get_int("tm_autostore"))  tm_rows_reordered ();
1801
 
    sort_window_update ();
1802
 
 
1803
 
    /* stable sorting: index original order */
1804
 
    tracks = tm_get_all_tracks ();
1805
 
    /* make numbering ascending or decending depending on sort order
1806
 
       (then we don't have to worry about the sort order when doing
1807
 
       the comparison in tm_data_compare_func() */
1808
 
    if (order == GTK_SORT_ASCENDING)
1809
 
    {
1810
 
        i=0;
1811
 
        inc = 1;
1812
 
    }
1813
 
    else
1814
 
    {
1815
 
        i=-1;
1816
 
        inc = -1;
1817
 
    }
1818
 
    for (gl=tracks; gl; gl=gl->next)
1819
 
    {
1820
 
        ExtraTrackData *etr;
1821
 
        Track *tr = gl->data;
1822
 
        g_return_if_fail (tr);
1823
 
        etr = tr->userdata;
1824
 
        g_return_if_fail (etr);
1825
 
        etr->sortindex = i;
1826
 
        i+=inc;
1827
 
    }
1828
 
    g_list_free (tracks);
1829
 
}
1830
 
 
1831
 
 
1832
 
void tm_sort (TM_item col, GtkSortType order)
1833
 
{
1834
 
    if (track_treeview)
1835
 
    {
1836
 
        GtkTreeModel *model= gtk_tree_view_get_model (track_treeview);
1837
 
        if (order != SORT_NONE)
1838
 
        {
1839
 
            gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
1840
 
                                                  col, order);
1841
 
        }
1842
 
        else
1843
 
        { /* only unsort if treeview is sorted */
1844
 
            gint column;
1845
 
            GtkSortType order;
1846
 
            if (gtk_tree_sortable_get_sort_column_id
1847
 
                (GTK_TREE_SORTABLE (model), &column, &order))
1848
 
            {
1849
 
                /* column == -2 actually is not defined, but it means
1850
 
                   that the model is unsorted. The sortable interface
1851
 
                   is badly implemented in gtk 2.4 */
1852
 
                if (column != -2)
1853
 
                    tm_unsort ();
1854
 
            }
1855
 
        }
1856
 
    }
1857
 
}
1858
 
 
1859
 
 
1860
 
 
1861
 
 
1862
 
 
1863
 
/* Adds the columns to our track_treeview */
1864
 
static GtkTreeViewColumn *tm_add_column (TM_item tm_item, gint pos)
1865
 
{
1866
 
  GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
1867
 
  GtkTreeViewColumn *col = NULL;
1868
 
  const gchar *text;
1869
 
  GtkCellRenderer *renderer = NULL;  /* default */
1870
 
  GtkTooltips *tt;
1871
 
 
1872
 
  g_return_val_if_fail (gtkpod_window, NULL);
1873
 
  tt = g_object_get_data (G_OBJECT (gtkpod_window), "main_tooltips");
1874
 
  g_return_val_if_fail (tt, NULL);
1875
 
 
1876
 
  g_return_val_if_fail (tm_item >= 0, NULL);
1877
 
  g_return_val_if_fail (tm_item < TM_NUM_COLUMNS, NULL);
1878
 
 
1879
 
  text = gettext (get_tm_string (tm_item));
1880
 
 
1881
 
  g_return_val_if_fail (text, NULL);
1882
 
 
1883
 
  col = gtk_tree_view_column_new ();
1884
 
 
1885
 
  switch (tm_item)
1886
 
  {
1887
 
  case TM_COLUMN_TITLE:
1888
 
      /* Add additional toggle box for 'checked' property */
1889
 
      renderer = gtk_cell_renderer_toggle_new ();
1890
 
      g_object_set_data (G_OBJECT (renderer), "column",
1891
 
                         (gint *)tm_item);
1892
 
      g_signal_connect (G_OBJECT (renderer), "toggled",
1893
 
                        G_CALLBACK (tm_cell_toggled), model);
1894
 
      gtk_tree_view_column_pack_start (col, renderer, FALSE);
1895
 
      gtk_tree_view_column_set_cell_data_func (col, renderer,
1896
 
                                               tm_cell_data_func_toggle,
1897
 
                                               NULL, NULL);
1898
 
      renderer = NULL;
1899
 
      break;
1900
 
  case TM_COLUMN_ARTIST:
1901
 
  case TM_COLUMN_ALBUM:
1902
 
  case TM_COLUMN_GENRE:
1903
 
  case TM_COLUMN_COMPOSER:
1904
 
  case TM_COLUMN_COMMENT:
1905
 
  case TM_COLUMN_FILETYPE:
1906
 
  case TM_COLUMN_GROUPING:
1907
 
  case TM_COLUMN_BITRATE:
1908
 
  case TM_COLUMN_SAMPLERATE:
1909
 
  case TM_COLUMN_BPM:
1910
 
  case TM_COLUMN_CATEGORY:
1911
 
  case TM_COLUMN_DESCRIPTION:
1912
 
  case TM_COLUMN_PODCASTURL:
1913
 
  case TM_COLUMN_PODCASTRSS:
1914
 
  case TM_COLUMN_SUBTITLE:
1915
 
  case TM_COLUMN_PC_PATH:
1916
 
  case TM_COLUMN_IPOD_PATH:
1917
 
  case TM_COLUMN_THUMB_PATH:
1918
 
  case TM_COLUMN_SIZE:
1919
 
      break;
1920
 
  /* for some column names we want to use shorter alternatives to
1921
 
     get_tm_string() */
1922
 
  case TM_COLUMN_RATING:
1923
 
      text = _("Rtng");
1924
 
      break;
1925
 
  case TM_COLUMN_TRACK_NR:
1926
 
      text = _("#");
1927
 
      break;
1928
 
  case TM_COLUMN_CD_NR:
1929
 
      text = _("CD");
1930
 
      break;
1931
 
  case TM_COLUMN_IPOD_ID:
1932
 
      text = _("ID");
1933
 
      break;
1934
 
  case TM_COLUMN_TRANSFERRED:
1935
 
      text = _("Trnsfrd");
1936
 
      renderer = gtk_cell_renderer_toggle_new ();
1937
 
      break;
1938
 
  case TM_COLUMN_COMPILATION:
1939
 
      text = _("Cmpl");
1940
 
      renderer = gtk_cell_renderer_toggle_new ();
1941
 
      g_signal_connect (G_OBJECT (renderer), "toggled",
1942
 
                        G_CALLBACK (tm_cell_toggled), model);
1943
 
      break;
1944
 
  case TM_COLUMN_TRACKLEN:
1945
 
      text = _("Time");
1946
 
      break;
1947
 
  case TM_COLUMN_PLAYCOUNT:
1948
 
      text = _("Plycnt");
1949
 
      break;
1950
 
  case TM_COLUMN_TIME_PLAYED:
1951
 
      text = _("Played");
1952
 
      break;
1953
 
  case TM_COLUMN_TIME_MODIFIED:
1954
 
      text = _("Modified");
1955
 
      break;
1956
 
  case TM_COLUMN_TIME_ADDED:
1957
 
      text = _("Added");
1958
 
      break;
1959
 
  case TM_COLUMN_TIME_RELEASED:
1960
 
      text = _("Released");
1961
 
      break;
1962
 
  case TM_COLUMN_YEAR:
1963
 
      text = _("Year");
1964
 
      break;
1965
 
  case TM_COLUMN_VOLUME:
1966
 
      text = _("Vol.");
1967
 
      break;
1968
 
  case TM_COLUMN_SOUNDCHECK:
1969
 
      text = _("Sndchk.");
1970
 
      break;
1971
 
  case TM_NUM_COLUMNS:
1972
 
      g_return_val_if_reached (NULL);
1973
 
      break;
1974
 
  }
1975
 
 
1976
 
  if (!renderer)
1977
 
  {   /* text renderer -- editable/not editable is done in
1978
 
         tm_cell_data_func() */
1979
 
      renderer = gtk_cell_renderer_text_new ();
1980
 
      g_signal_connect (G_OBJECT (renderer), "edited",
1981
 
                        G_CALLBACK (tm_cell_edited), model);
1982
 
  }
1983
 
 
1984
 
  g_object_set_data (G_OBJECT (renderer), "column",
1985
 
                     (gint *)tm_item);
1986
 
 
1987
 
  gtk_tree_view_column_set_title (col, text);
1988
 
  gtk_tree_view_column_pack_start (col, renderer, FALSE);
1989
 
  gtk_tree_view_column_set_cell_data_func (col, renderer,
1990
 
                                           tm_cell_data_func, NULL, NULL);
1991
 
  gtk_tree_view_column_set_sort_column_id (col, tm_item);
1992
 
  gtk_tree_view_column_set_resizable (col, TRUE);
1993
 
/*     gtk_tree_view_column_set_clickable(column, TRUE); */
1994
 
  gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
1995
 
  gtk_tree_view_column_set_fixed_width (col,
1996
 
                                        prefs_get_int_index("tm_col_width", tm_item));
1997
 
  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), tm_item,
1998
 
                                   tm_data_compare_func, NULL, NULL);
1999
 
  gtk_tree_view_column_set_reorderable (col, TRUE);
2000
 
  gtk_tree_view_insert_column (track_treeview, col, pos);
2001
 
  tm_columns[tm_item] = col;
2002
 
 
2003
 
  if (pos != -1)
2004
 
  {
2005
 
      gtk_tree_view_column_set_visible (col,
2006
 
                                        prefs_get_int_index("col_visible", tm_item));
2007
 
  }
2008
 
  if (get_tm_tooltip (tm_item))
2009
 
      gtk_tooltips_set_tip (tt, col->button, 
2010
 
                            gettext (get_tm_tooltip (tm_item)),
2011
 
                            NULL);
2012
 
  return col;
2013
 
}
2014
 
 
2015
 
 
2016
 
/* Adds the columns to our track_treeview */
2017
 
static void tm_add_columns (void)
2018
 
{
2019
 
    gint i;
2020
 
 
2021
 
    for (i=0; i<TM_NUM_COLUMNS; ++i)
2022
 
    {
2023
 
        tm_add_column (prefs_get_int_index("col_order", i), -1);
2024
 
    }
2025
 
    tm_show_preferred_columns();
2026
 
}
2027
 
 
2028
 
static void tm_select_current_position (gint x, gint y)
2029
 
{
2030
 
    if (track_treeview)
2031
 
    {
2032
 
        GtkTreePath *path;
2033
 
 
2034
 
        gtk_tree_view_get_path_at_pos (track_treeview,
2035
 
                                       x, y, &path, NULL, NULL, NULL);
2036
 
        if (path)
2037
 
        {
2038
 
            GtkTreeSelection *ts = gtk_tree_view_get_selection (track_treeview);
2039
 
            gtk_tree_selection_select_path (ts, path);
2040
 
            gtk_tree_path_free (path);
2041
 
        }
2042
 
    }
2043
 
}
2044
 
 
2045
 
static gboolean
2046
 
tm_button_press_event(GtkWidget *w, GdkEventButton *e, gpointer data)
2047
 
{
2048
 
    if(w && e)
2049
 
    {
2050
 
        switch(e->button)
2051
 
        {
2052
 
        case 1:
2053
 
/*
2054
 
            printf ("Pressed in cell %d (%f/%f)\n\n",
2055
 
                    tree_view_get_cell_from_pos(GTK_TREE_VIEW(w),
2056
 
                                                (guint)e->x, (guint)e->y, NULL),
2057
 
                    e->x, e->y);
2058
 
*/
2059
 
            break;
2060
 
        case 3:
2061
 
            tm_select_current_position (e->x, e->y);
2062
 
            tm_context_menu_init ();
2063
 
            return TRUE;
2064
 
        default:
2065
 
            break;
2066
 
        }
2067
 
    }
2068
 
    return(FALSE);
2069
 
}
2070
 
 
2071
 
/* called when the track selection changes */
2072
 
static void
2073
 
tm_selection_changed_event(GtkTreeSelection *selection, gpointer data)
2074
 
{
2075
 
    GtkTreeView *treeview = gtk_tree_selection_get_tree_view (selection);
2076
 
    GtkTreePath *path;
2077
 
    GtkTreeViewColumn *column;
2078
 
    TM_item col_id;
2079
 
 
2080
 
    gtk_tree_view_get_cursor (treeview, &path, &column);
2081
 
    if (path)
2082
 
    {
2083
 
        col_id = tm_lookup_col_id (column);
2084
 
        if (col_id != -1)  tm_set_search_column (col_id);
2085
 
    }
2086
 
    info_update_track_view_selected ();
2087
 
}
2088
 
 
2089
 
 
2090
 
/* Create tracks treeview */
2091
 
void tm_create_treeview (void)
2092
 
{
2093
 
  GtkTreeModel *model = NULL;
2094
 
  GtkWidget *track_window = gtkpod_xml_get_widget (main_window_xml, "track_window");
2095
 
  GtkTreeSelection *select;
2096
 
  gint col;
2097
 
  GtkWidget *stv = gtk_tree_view_new ();
2098
 
 
2099
 
  /* create tree view */
2100
 
  if (track_treeview)
2101
 
  {   /* delete old tree view */
2102
 
      model = gtk_tree_view_get_model (track_treeview);
2103
 
      /* FIXME: how to delete model? */
2104
 
      gtk_widget_destroy (GTK_WIDGET (track_treeview));
2105
 
  }
2106
 
  track_treeview = GTK_TREE_VIEW (stv);
2107
 
  gtk_widget_show (stv);
2108
 
  gtk_container_add (GTK_CONTAINER (track_window), stv);
2109
 
  /* create model (we only need one column for the model -- only a
2110
 
   * pointer to the track has to be stored) */
2111
 
  model = GTK_TREE_MODEL (
2112
 
      gtk_list_store_new (1, G_TYPE_POINTER));
2113
 
  gtk_tree_view_set_model (track_treeview, GTK_TREE_MODEL (model));
2114
 
  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (track_treeview), TRUE);
2115
 
  gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (track_treeview), 
2116
 
                                       tm_search_equal_func,
2117
 
                                       NULL,
2118
 
                                       NULL);
2119
 
  select = gtk_tree_view_get_selection (track_treeview);
2120
 
  gtk_tree_selection_set_mode (select,
2121
 
                               GTK_SELECTION_MULTIPLE);
2122
 
  g_signal_connect (G_OBJECT (select) , "changed",
2123
 
                    G_CALLBACK (tm_selection_changed_event),
2124
 
                    NULL);
2125
 
  tm_add_columns ();
2126
 
 
2127
 
/*   gtk_drag_source_set (GTK_WIDGET (track_treeview), GDK_BUTTON1_MASK, */
2128
 
/*                     tm_drag_types, TGNR (tm_drag_types), */
2129
 
/*                     GDK_ACTION_COPY|GDK_ACTION_MOVE); */
2130
 
/*   gtk_tree_view_enable_model_drag_dest(track_treeview, tm_drop_types, */
2131
 
/*                                     TGNR (tm_drop_types), */
2132
 
/*                                     GDK_ACTION_COPY|GDK_ACTION_MOVE); */
2133
 
/*   /\* need the gtk_drag_dest_set() with no actions ("0") so that the */
2134
 
/*      data_received callback gets the correct info value. This is most */
2135
 
/*      likely a bug... *\/ */
2136
 
/*   gtk_drag_dest_set_target_list (GTK_WIDGET (track_treeview), */
2137
 
/*                               gtk_target_list_new (tm_drop_types, */
2138
 
/*                                                    TGNR (tm_drop_types))); */
2139
 
 
2140
 
 
2141
 
  gtk_drag_source_set (GTK_WIDGET (track_treeview),
2142
 
                       GDK_BUTTON1_MASK,
2143
 
                       tm_drag_types, TGNR (tm_drag_types),
2144
 
                       GDK_ACTION_COPY|GDK_ACTION_MOVE);
2145
 
  gtk_drag_dest_set (GTK_WIDGET (track_treeview),
2146
 
                     0,
2147
 
                     tm_drop_types, TGNR (tm_drop_types),
2148
 
                     GDK_ACTION_COPY|GDK_ACTION_MOVE);
2149
 
 
2150
 
 
2151
 
  g_signal_connect ((gpointer) track_treeview, "drag-begin",
2152
 
                    G_CALLBACK (tm_drag_begin),
2153
 
                    NULL);
2154
 
 
2155
 
  g_signal_connect ((gpointer) track_treeview, "drag-data-delete",
2156
 
                    G_CALLBACK (tm_drag_data_delete),
2157
 
                    NULL);
2158
 
 
2159
 
  g_signal_connect ((gpointer) track_treeview, "drag-data-get",
2160
 
                    G_CALLBACK (tm_drag_data_get),
2161
 
                    NULL);
2162
 
 
2163
 
  g_signal_connect ((gpointer) track_treeview, "drag-data-received",
2164
 
                    G_CALLBACK (tm_drag_data_received),
2165
 
                    NULL);
2166
 
 
2167
 
  g_signal_connect ((gpointer) track_treeview, "drag-drop",
2168
 
                    G_CALLBACK (tm_drag_drop),
2169
 
                    NULL);
2170
 
 
2171
 
  g_signal_connect ((gpointer) track_treeview, "drag-end",
2172
 
                    G_CALLBACK (tm_drag_end),
2173
 
                    NULL);
2174
 
 
2175
 
  g_signal_connect ((gpointer) track_treeview, "drag-leave",
2176
 
                    G_CALLBACK (tm_drag_leave),
2177
 
                    NULL);
2178
 
 
2179
 
  g_signal_connect ((gpointer) track_treeview, "drag-motion",
2180
 
                    G_CALLBACK (tm_drag_motion),
2181
 
                    NULL);
2182
 
 
2183
 
  g_signal_connect_after ((gpointer) stv, "key_release_event",
2184
 
                          G_CALLBACK (on_track_treeview_key_release_event),
2185
 
                          NULL);
2186
 
  g_signal_connect ((gpointer) track_treeview, "button-press-event",
2187
 
                    G_CALLBACK (tm_button_press_event),
2188
 
                    NULL);
2189
 
  g_signal_connect (G_OBJECT (model), "sort-column-changed",
2190
 
                    G_CALLBACK (tm_sort_column_changed),
2191
 
                    (gpointer)0);
2192
 
 
2193
 
  /* initialize sorting */
2194
 
  tm_sort (prefs_get_int("tm_sortcol"), prefs_get_int("tm_sort_"));
2195
 
  /* set correct column for typeahead */
2196
 
  if (prefs_get_int_value (TM_PREFS_SEARCH_COLUMN, &col))
2197
 
  {
2198
 
      tm_set_search_column (col);
2199
 
  }
2200
 
  else
2201
 
  {   /* reasonable default */
2202
 
      tm_set_search_column (TM_COLUMN_TITLE);
2203
 
  }
2204
 
}
2205
 
 
2206
 
 
2207
 
void
2208
 
tm_show_preferred_columns(void)
2209
 
{
2210
 
    GtkTreeViewColumn *tvc = NULL;
2211
 
    gboolean visible;
2212
 
    gint i;
2213
 
 
2214
 
    for (i=0; i<TM_NUM_COLUMNS; ++i)
2215
 
    {
2216
 
        tvc = gtk_tree_view_get_column (track_treeview, i);
2217
 
        visible = prefs_get_int_index("col_visible", 
2218
 
      prefs_get_int_index("col_order", i));
2219
 
        gtk_tree_view_column_set_visible (tvc, visible);
2220
 
    }
2221
 
}
2222
 
 
2223
 
 
2224
 
/* update the cfg structure (preferences) with the current sizes /
2225
 
   positions (called by display_update_default_sizes():
2226
 
   column widths of track model */
2227
 
void tm_update_default_sizes (void)
2228
 
{
2229
 
    gint i;
2230
 
    GtkTreeViewColumn *col;
2231
 
    gint col_width;
2232
 
 
2233
 
    /* column widths */
2234
 
    for (i=0; i<TM_NUM_COLUMNS; ++i)
2235
 
    {
2236
 
        col = tm_columns [i];
2237
 
        if (col)
2238
 
        {
2239
 
    col_width = gtk_tree_view_column_get_width (col);
2240
 
    
2241
 
    if (col_width > 0)
2242
 
            prefs_set_int_index ("tm_col_width", i, col_width);
2243
 
    else
2244
 
      prefs_set_int_index ("tm_col_width", i, 80);
2245
 
   
2246
 
        }
2247
 
    }
2248
 
}
2249
 
 
2250
 
 
2251
 
/* get the TM_ITEM column id for @column. Returns -1 if column could
2252
 
   not be found */
2253
 
static TM_item tm_lookup_col_id (GtkTreeViewColumn *column)
2254
 
{
2255
 
    gint i;
2256
 
 
2257
 
    if (column)
2258
 
    {
2259
 
        for (i=0; i<TM_NUM_COLUMNS; ++i)
2260
 
        {
2261
 
            if (column == tm_columns[i]) return i;
2262
 
        }
2263
 
    }
2264
 
    return -1;
2265
 
}
2266
 
 
2267
 
 
2268
 
/* Compare function to avoid sorting */
2269
 
static gint tm_nosort_comp (GtkTreeModel *model,
2270
 
                            GtkTreeIter *a,
2271
 
                            GtkTreeIter *b,
2272
 
                            gpointer user_data)
2273
 
{
2274
 
    return 0;
2275
 
}
2276
 
 
2277
 
 
2278
 
/* Disable sorting of the view during lengthy updates. */
2279
 
/* @enable: TRUE: enable, FALSE: disable */
2280
 
void tm_enable_disable_view_sort (gboolean enable)
2281
 
{
2282
 
    static gint disable_count = 0;
2283
 
 
2284
 
    if (enable)
2285
 
    {
2286
 
        disable_count--;
2287
 
        if (disable_count < 0)
2288
 
            fprintf (stderr, "Programming error: disable_count < 0\n");
2289
 
        if (disable_count == 0 && track_treeview)
2290
 
        {
2291
 
            if ((prefs_get_int("tm_sort_") != SORT_NONE) &&
2292
 
                sorting_disabled())
2293
 
            {
2294
 
                /* Re-enable sorting */
2295
 
                GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
2296
 
                if (BROKEN_GTK_TREE_SORT)
2297
 
                {
2298
 
                    gtk_tree_sortable_set_sort_func (
2299
 
                        GTK_TREE_SORTABLE (model),
2300
 
                        prefs_get_int("tm_sortcol"),
2301
 
                        tm_data_compare_func, NULL, NULL);
2302
 
                }
2303
 
                else
2304
 
                {
2305
 
                    gtk_tree_sortable_set_sort_column_id (
2306
 
                        GTK_TREE_SORTABLE (model),
2307
 
                        prefs_get_int("tm_sortcol"),
2308
 
                        prefs_get_int("tm_sort_"));
2309
 
                }
2310
 
            }
2311
 
        }
2312
 
    }
2313
 
    else
2314
 
    {
2315
 
        if (disable_count == 0 && track_treeview)
2316
 
        {
2317
 
            if ((prefs_get_int("tm_sort_") != SORT_NONE) &&
2318
 
                sorting_disabled ())
2319
 
            {
2320
 
                /* Disable sorting */
2321
 
                GtkTreeModel *model = gtk_tree_view_get_model (track_treeview);
2322
 
                if (BROKEN_GTK_TREE_SORT)
2323
 
                {
2324
 
                    gtk_tree_sortable_set_sort_func (
2325
 
                        GTK_TREE_SORTABLE (model),
2326
 
                        prefs_get_int("tm_sortcol"),
2327
 
                        tm_nosort_comp, NULL, NULL);
2328
 
                }
2329
 
                else
2330
 
                {
2331
 
                    gtk_tree_sortable_set_sort_column_id (
2332
 
                        GTK_TREE_SORTABLE (model),
2333
 
                        GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
2334
 
                        prefs_get_int("tm_sort_"));
2335
 
                }
2336
 
            }
2337
 
        }
2338
 
        disable_count++;
2339
 
    }
2340
 
}
2341
 
 
2342
 
 
2343
 
 
2344
 
/* Callback for adding tracks within tm_add_filelist */
2345
 
void tm_addtrackfunc (Playlist *plitem, Track *track, gpointer data)
2346
 
{
2347
 
    struct asf_data *asf = (struct asf_data *)data;
2348
 
    GtkTreeModel *model;
2349
 
    GtkTreeIter new_iter;
2350
 
 
2351
 
    model = gtk_tree_view_get_model (track_treeview);
2352
 
 
2353
 
/*    printf("plitem: %p\n", plitem);
2354
 
      if (plitem) printf("plitem->type: %d\n", plitem->type);*/
2355
 
    /* add to playlist but not to the display */
2356
 
    gp_playlist_add_track (plitem, track, FALSE);
2357
 
 
2358
 
    /* create new iter in track view */
2359
 
    switch (asf->pos)
2360
 
    {
2361
 
    case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
2362
 
    case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
2363
 
    case GTK_TREE_VIEW_DROP_AFTER:
2364
 
        gtk_list_store_insert_after (GTK_LIST_STORE (model),
2365
 
                                     &new_iter, asf->to_iter);
2366
 
        break;
2367
 
    case GTK_TREE_VIEW_DROP_BEFORE:
2368
 
        gtk_list_store_insert_before (GTK_LIST_STORE (model),
2369
 
                                      &new_iter, asf->to_iter);
2370
 
        break;
2371
 
    }
2372
 
    /* set the iter */
2373
 
    tm_add_track_to_track_model (track, &new_iter);
2374
 
}
2375
 
 
2376
 
 
2377
 
/* DND: insert a list of files before/after @path
2378
 
   @data: list of files
2379
 
   @path: where to drop (NULL to drop at the end)
2380
 
   @pos:  before/after... (ignored if @path is NULL)
2381
 
*/
2382
 
gboolean tm_add_filelist (gchar *data,
2383
 
                          GtkTreePath *path,
2384
 
                          GtkTreeViewDropPosition pos)
2385
 
{
2386
 
    GtkTreeModel *model;
2387
 
    gchar *buf = NULL, *use_data;
2388
 
    gchar **files, **filep;
2389
 
    Playlist *current_playlist = pm_get_selected_playlist ();
2390
 
 
2391
 
    g_return_val_if_fail (data, FALSE);
2392
 
    g_return_val_if_fail (*data, FALSE);
2393
 
    g_return_val_if_fail (current_playlist, FALSE);
2394
 
 
2395
 
    model = gtk_tree_view_get_model (track_treeview);
2396
 
    g_return_val_if_fail (model, FALSE);
2397
 
    if (path)
2398
 
    {
2399
 
    }
2400
 
 
2401
 
    if (pos != GTK_TREE_VIEW_DROP_BEFORE)
2402
 
    {   /* need to reverse the list of files -- otherwise wie add them
2403
 
         * in reverse order */
2404
 
        /* split the path list into individual strings */
2405
 
        gint len = strlen (data) + 1;
2406
 
        files = g_strsplit (data, "\n", -1);
2407
 
        filep = files;
2408
 
        /* find the end of the list */
2409
 
        while (*filep) ++filep;
2410
 
        /* reserve memory */
2411
 
        buf = g_malloc0 (len);
2412
 
        /* reverse the list */
2413
 
        while (filep != files)
2414
 
        {
2415
 
            --filep;
2416
 
            g_strlcat (buf, *filep, len);
2417
 
            g_strlcat (buf, "\n", len);
2418
 
        }
2419
 
        g_strfreev (files);
2420
 
        use_data = buf;
2421
 
    }
2422
 
    else
2423
 
    {
2424
 
        use_data = data;
2425
 
    }
2426
 
 
2427
 
/*     printf("filelist: (%s) -> (%s)\n", data, use_data); */
2428
 
    /* initialize add-track-struct */
2429
 
    if (path)
2430
 
    {   /* add where specified (@path/@pos) */
2431
 
        GtkTreeIter to_iter;
2432
 
        struct asf_data asf;
2433
 
        if (!gtk_tree_model_get_iter (model, &to_iter, path))
2434
 
            g_return_val_if_reached (FALSE);
2435
 
        asf.to_iter = &to_iter;
2436
 
        asf.pos = pos;
2437
 
        add_text_plain_to_playlist (current_playlist->itdb,
2438
 
                                    current_playlist, use_data, 0,
2439
 
                                    tm_addtrackfunc, &asf);
2440
 
    }
2441
 
    else
2442
 
    {   /* add to the end */
2443
 
        add_text_plain_to_playlist (current_playlist->itdb,
2444
 
                                    current_playlist, use_data, 0,
2445
 
                                    NULL, NULL);
2446
 
    }
2447
 
    tm_rows_reordered ();
2448
 
    C_FREE (buf);
2449
 
    return TRUE;
2450
 
}