root/lang/c/sonydb/frontend.cpp

Revision 18890, 35.4 kB (checked in by mattn, 3 months ago)

デフォルトで検知するデバイス(WALKMANマウント先)を指定出来る様修正

Line 
1#ifdef GUI
2#include <gtk/gtk.h>
3#include <gdk/gdkkeys.h>
4#include <gdk/gdkkeysyms.h>
5#include "images.h"
6#endif
7#include <id3.h>
8#include "sonydb.h"
9
10
11#ifdef __GNUC__
12#undef _WIN32
13#endif
14
15#ifdef GUI
16enum {
17COL_ICON,
18COL_TEXT,
19COL_SONG,
20COL_MAX
21};
22#define EDIT_TYPE_ARTIST 1
23#define EDIT_TYPE_ALBUM 2
24#define EDIT_TYPE_TITLE 3
25#endif
26
27static char* get_genre(const char* src)
28{
29        const char* ptr = src;
30        while(*ptr && !isdigit(*ptr)) ptr++;
31        switch(atol(ptr)) {
32        case 0: return "Blues";
33        case 1: return "Classic Rock";
34        case 2: return "Country";
35        case 3: return "Dance";
36        case 4: return "Disco";
37        case 5: return "Funk";
38        case 6: return "Grunge";
39        case 7: return "Hip-Hop";
40        case 8: return "Jazz";
41        case 9: return "Metal";
42        case 10: return "New Age";
43        case 11: return "Oldies";
44        case 12: return "Other";
45        case 13: return "Pop";
46        case 14: return "R?";
47        case 15: return "Rap";
48        case 16: return "Reggae";
49        case 17: return "Rock";
50        case 18: return "Techno";
51        case 19: return "Industrial";
52        case 20: return "Alternative";
53        case 21: return "Ska";
54        case 22: return "Death Metal";
55        case 23: return "Pranks";
56        case 24: return "Soundtrack";
57        case 25: return "Euro-Techno";
58        case 26: return "Ambient";
59        case 27: return "Trip-Hop";
60        case 28: return "Vocal";
61        case 29: return "Jazz+Funk";
62        case 30: return "Fusion";
63        case 31: return "Trance";
64        case 32: return "Classical";
65        case 33: return "Instrumental";
66        case 34: return "Acid";
67        case 35: return "House";
68        case 36: return "Game";
69        case 37: return "Sound Clip";
70        case 38: return "Gospel";
71        case 39: return "Noise";
72        case 40: return "AlternRock";
73        case 41: return "Bass";
74        case 42: return "Soul";
75        case 43: return "Punk";
76        case 44: return "Space";
77        case 45: return "Meditative";
78        case 46: return "Instrumental Pop";
79        case 47: return "Instrumental Rock";
80        case 48: return "Ethnic";
81        case 49: return "Gothic";
82        case 50: return "Darkwave";
83        case 51: return "Techno-Industrial";
84        case 52: return "Electronic";
85        case 53: return "Pop-Folk";
86        case 54: return "Eurodance";
87        case 55: return "Dream";
88        case 56: return "Southern Rock";
89        case 57: return "Comedy";
90        case 58: return "Cult";
91        case 59: return "Gangsta";
92        case 60: return "Top 40";
93        case 61: return "Christian Rap";
94        case 62: return "Pop/Funk";
95        case 63: return "Jungle";
96        case 64: return "Native American";
97        case 65: return "Cabaret";
98        case 66: return "New Wave";
99        case 67: return "Psychadelic";
100        case 68: return "Rave";
101        case 69: return "Showtunes";
102        case 70: return "Trailer";
103        case 71: return "Lo-Fi";
104        case 72: return "Tribal";
105        case 73: return "Acid Punk";
106        case 74: return "Acid Jazz";
107        case 75: return "Polka";
108        case 76: return "Retro";
109        case 77: return "Musical";
110        case 78: return "Rock & Roll";
111        case 79: return "Hard Rock";
112        case 80: return "Folk";
113        case 81: return "Folk-Rock";
114        case 82: return "National Folk";
115        case 83: return "Swing";
116        case 84: return "Fast Fusion";
117        case 85: return "Bebob";
118        case 86: return "Latin";
119        case 87: return "Revival";
120        case 88: return "Celtic";
121        case 89: return "Bluegrass";
122        case 90: return "Avantgarde";
123        case 91: return "Gothic Rock";
124        case 92: return "Progressive Rock";
125        case 93: return "Psychedelic Rock";
126        case 94: return "Symphonic Rock";
127        case 95: return "Slow Rock";
128        case 96: return "Big Band";
129        case 97: return "Chorus";
130        case 98: return "Easy Listening";
131        case 99: return "Acoustic";
132        case 100: return "Humour";
133        case 101: return "Speech";
134        case 102: return "Chanson";
135        case 103: return "Opera";
136        case 104: return "Chamber Music";
137        case 105: return "Sonata";
138        case 106: return "Symphony";
139        case 107: return "Booty Bass";
140        case 108: return "Primus";
141        case 109: return "Porn Groove";
142        case 110: return "Satire";
143        case 111: return "Slow Jam";
144        case 112: return "Club";
145        case 113: return "Tango";
146        case 114: return "Samba";
147        case 115: return "Folklore";
148        case 116: return "Ballad";
149        case 117: return "Power Ballad";
150        case 118: return "Rhythmic Soul";
151        case 119: return "Freestyle";
152        case 120: return "Duet";
153        case 121: return "Punk Rock";
154        case 122: return "Drum Solo";
155        case 123: return "A capella";
156        case 124: return "Euro-House";
157        case 125: return "Dance Hall";
158        }
159        return "";
160}
161
162static void print_song(Song* song)
163{
164        printf("songs(%04d): %s,%s,%s\n\tencoding=%s\n\tfilename=%s\n\tgenre=%s\n\tsonglen=%d\n\ttrack_nr=%d\n\tyear=%d\n",
165                        song->sonyDbOrder,
166                        song->artist,
167                        song->album,
168                        song->title,
169                        song->encoding,
170                        song->filename,
171                        song->genre,
172                        song->songlen,
173                        song->track_nr,
174                        song->year
175                        );
176}
177
178static void deleteSongPtr(Song *song)
179{
180     free(song->album);
181     free(song->artist);
182     free(song->title);
183     free(song->genre);
184     free(song->filename);
185     free(song);
186}
187
188std::string wstring2string(const wchar_t* str)
189{
190        std::string ret;
191#ifdef _WIN32
192        UINT codePage = GetACP();
193        size_t mbssize = WideCharToMultiByte(CP_ACP,0,(LPCWSTR)str,-1,NULL,0,NULL,NULL);
194        char* pszStr = new char[mbssize+1];
195        WideCharToMultiByte(codePage, 0, (LPCWSTR)str, -1, pszStr, mbssize, NULL, NULL);
196        pszStr[mbssize] = '\0';
197        ret = pszStr;
198        delete [] pszStr;
199#else
200        if (str) {
201                size_t mbssize = wcstombs(0, str, 0)*2;
202                char* dest = (char*)malloc(mbssize+1);
203                if (dest) {
204                        wcstombs(dest, str, mbssize);
205                        ret = dest;
206                        free(dest);
207                }
208        }
209#endif
210        return ret;
211}
212
213wstring string2wstring(const char* str)
214{
215        wstring ret;
216#ifdef _WIN32
217        size_t in_len = strlen(str);
218        UINT codePage = GetACP();
219        size_t wcssize = MultiByteToWideChar(codePage, MB_PRECOMPOSED, str,in_len,  NULL, 0);
220        wchar_t* pszStr = new wchar_t[wcssize + 1];
221        MultiByteToWideChar(codePage, MB_PRECOMPOSED, str, in_len, pszStr, wcssize + 1);
222        pszStr[wcssize] = '\0';
223        ret = pszStr;
224        delete [] pszStr;
225#else
226        if (str) {
227                size_t wcssize = strlen(str)*sizeof(wchar_t);
228                wchar_t* dest = (wchar_t*)malloc(wcssize+1);
229                if (dest) {
230                        mbstowcs(dest, str, wcssize);
231                        ret = dest;
232                        free(dest);
233                }
234        }
235#endif
236        return ret;
237}
238
239char* get_tag(ID3Tag* tag, ID3_FrameID id)
240{
241        unicode_t wbuff[BUFSIZ] = {0};
242        ID3Frame* frame = ID3Tag_FindFrameWithID(tag, id);
243        ID3Field* field = ID3Frame_GetField(frame, ID3FN_TEXT);
244        memset(wbuff, 0, sizeof(wbuff));
245        if (ID3Field_GetUNICODE(field, wbuff, ID3Field_Size(field)/sizeof(unicode_t)) == 0) {
246                char buff[BUFSIZ] = {0};
247                ID3Field_GetASCII(field, buff, ID3Field_Size(field));
248                return strdup(buff);
249        }
250        return utf16_to_ansi(wbuff, sizeof(wbuff)/sizeof(unicode_t), true);
251}
252
253#ifdef GUI
254void rebuild_tree(GtkWidget* widget, SonyDb* sonydb, bool reload)
255{
256        GtkTreeModel* model;
257        GtkTreeStore* store;
258        GtkWidget* button;
259        GtkTreeIter iter_artist, iter_album, iter_title;
260        vector<Song*> songs;
261        vector<Song*>::iterator itsongs;
262
263        if (reload) sonydb->readAllTracks();
264        songs = sonydb->getSongs();
265
266        store = (GtkTreeStore*)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
267        model = (GtkTreeModel*)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
268        gtk_tree_view_set_model(GTK_TREE_VIEW(widget), NULL);
269        gtk_tree_store_clear(store);
270        for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
271                Song* song = *itsongs;
272                if (song->statusOfSong == REMOVE_FROM_DEVICE) continue;
273                gchar* artist = g_locale_to_utf8(song->artist, -1, NULL, NULL, NULL);
274                gchar* album = g_locale_to_utf8(song->album, -1, NULL, NULL, NULL);
275                gchar* title = g_strdup_printf("%02d) %s", song->track_nr, g_locale_to_utf8(song->title, -1, NULL, NULL, NULL));
276
277                if (gtk_tree_model_get_iter_first(model, &iter_artist)) {
278                        gchar *str_data;
279                        while(true) {
280                                str_data = NULL;
281                                gtk_tree_model_get(model, &iter_artist, COL_TEXT, &str_data, -1);
282                                if (str_data && !strcmp(str_data, artist)) {
283                                        g_free(artist);
284                                        artist = NULL;
285                                        if (!gtk_tree_model_iter_children(model, &iter_album, &iter_artist))
286                                                break;
287                                        while(true) {
288                                                str_data = NULL;
289                                                gtk_tree_model_get(model, &iter_album, COL_TEXT, &str_data, -1);
290                                                if (str_data && !strcmp(str_data, album)) {
291                                                        g_free(album);
292                                                        album = NULL;
293                                                        if (!gtk_tree_model_iter_children(model, &iter_title, &iter_album))
294                                                                break;
295                                                        while(true) {
296                                                                str_data = NULL;
297                                                                gtk_tree_model_get(model, &iter_title, COL_TEXT, &str_data, -1);
298                                                                if (str_data && !strcmp(str_data, title)) {
299                                                                        g_free(title);
300                                                                        title = NULL;
301                                                                        break;
302                                                                }
303                                                                if (!gtk_tree_model_iter_next(model, &iter_title)) break;
304                                                        }
305                                                        break;
306                                                }
307                                                if (!gtk_tree_model_iter_next(model, &iter_album)) break;
308                                        }
309                                        break;
310                                }
311
312                                if (!gtk_tree_model_iter_next(model, &iter_artist)) break;
313                        }
314                }
315
316                GdkPixbuf* pixbuf;
317                GError* _error = NULL;
318#ifdef __IMAGES_H__
319                GdkPixbufLoader* loader;
320#endif
321
322                if (artist) {
323                        gtk_tree_store_append(store, &iter_artist, NULL);
324#ifdef __IMAGES_H__
325                        loader = gdk_pixbuf_loader_new_with_type("png", &_error);
326                        gdk_pixbuf_loader_write(loader, artist_image, sizeof(artist_image), &_error);
327                        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
328                        gdk_pixbuf_loader_close(loader, &_error);
329#else
330                        pixbuf = gdk_pixbuf_new_from_file("a1.png", &_error);
331#endif
332                        gtk_tree_store_set(
333                                        store,
334                                        &iter_artist,
335                                        COL_ICON,
336                                        pixbuf,
337                                        COL_TEXT,
338                                        artist,
339                                        -1);
340                }
341
342                if (album) {
343                        gtk_tree_store_append(store, &iter_album, &iter_artist);
344#ifdef __IMAGES_H__
345                        loader = gdk_pixbuf_loader_new_with_type("png", &_error);
346                        gdk_pixbuf_loader_write(loader, album_image, sizeof(album_image), &_error);
347                        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
348                        gdk_pixbuf_loader_close(loader, &_error);
349#else
350                        pixbuf = gdk_pixbuf_new_from_file("a2.png", &_error);
351#endif
352                        gtk_tree_store_set(
353                                        store,
354                                        &iter_album,
355                                        COL_ICON,
356                                        pixbuf,
357                                        COL_TEXT,
358                                        album,
359                                        -1);
360                }
361
362                if (title) {
363                        gtk_tree_store_append(store, &iter_title, &iter_album);
364#ifdef __IMAGES_H__
365                        loader = gdk_pixbuf_loader_new_with_type("png", &_error);
366                        gdk_pixbuf_loader_write(loader, title_image, sizeof(title_image), &_error);
367                        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
368                        gdk_pixbuf_loader_close(loader, &_error);
369#else
370                        pixbuf = gdk_pixbuf_new_from_file("a3.png", &_error);
371#endif
372                        gtk_tree_store_set(
373                                        store,
374                                        &iter_title,
375                                        COL_ICON,
376                                        pixbuf,
377                                        COL_TEXT,
378                                        title,
379                                        COL_SONG,
380                                        song,
381                                        -1);
382                }
383
384                if (artist) g_free(artist);
385                if (album) g_free(album);
386                if (title) g_free(title);
387        }
388        gtk_tree_view_set_model(GTK_TREE_VIEW(widget), model);
389        gtk_tree_view_expand_all(GTK_TREE_VIEW(widget));
390
391        bool enabled = sonydb->isPresent();
392        button = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "update");
393        gtk_widget_set_sensitive(button, enabled);
394        button = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "apply");
395        gtk_widget_set_sensitive(button, enabled && !reload);
396        button = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "clean");
397        gtk_widget_set_sensitive(button, enabled);
398}
399
400void on_update_clicked(GtkWidget* widget, gpointer user_data)
401{
402        SonyDb* sonydb = (SonyDb*)user_data;
403        GtkWidget* confirm;
404
405        confirm = gtk_message_dialog_new(
406                        NULL,
407                        (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
408                        GTK_MESSAGE_QUESTION,
409                        GTK_BUTTONS_NONE,
410                        "Are you sure you want to reset all changes?");
411        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_CANCEL, GTK_RESPONSE_NO);
412        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_APPLY, GTK_RESPONSE_YES);
413        gtk_dialog_set_default_response(GTK_DIALOG (confirm), GTK_RESPONSE_CANCEL);
414
415        gint response = gtk_dialog_run(GTK_DIALOG(confirm));
416        gtk_widget_destroy(confirm);
417
418        if (response == GTK_RESPONSE_YES) {
419                GtkWidget* treeview = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "treeview");
420                rebuild_tree(treeview, sonydb, true);
421        }
422}
423
424void on_clean_clicked(GtkWidget* widget, gpointer user_data)
425{
426        SonyDb* sonydb = (SonyDb*)user_data;
427        GtkWidget* confirm;
428
429        confirm = gtk_message_dialog_new(
430                        NULL,
431                        (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
432                        GTK_MESSAGE_QUESTION,
433                        GTK_BUTTONS_NONE,
434                        "Are you sure you want to clean all data?");
435        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_CANCEL, GTK_RESPONSE_NO);
436        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_APPLY, GTK_RESPONSE_YES);
437        gtk_dialog_set_default_response(GTK_DIALOG (confirm), GTK_RESPONSE_CANCEL);
438
439        gint response = gtk_dialog_run(GTK_DIALOG(confirm));
440        gtk_widget_destroy(confirm);
441
442        if (response == GTK_RESPONSE_YES) {
443                GtkWidget* treeview = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "treeview");
444                vector<Song*> songs;
445                vector<Song*>::iterator itsongs;
446                vector<Playlist*> plist;
447                vector<Playlist*>::iterator itplist;
448
449                plist = sonydb->getPlaylist();
450                for(itplist = plist.begin(); itplist != plist.end(); itplist++)
451                        sonydb->deletePlaylist((*itplist)->index, false);
452                songs = sonydb->getSongs();
453                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++)
454                        sonydb->delSong(*itsongs);
455                rebuild_tree(treeview, sonydb, false);
456        }
457}
458
459void on_apply_clicked(GtkWidget* widget, gpointer user_data)
460{
461        SonyDb* sonydb = (SonyDb*)user_data;
462        GtkWidget* confirm;
463
464        confirm = gtk_message_dialog_new(
465                        NULL,
466                        (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
467                        GTK_MESSAGE_QUESTION,
468                        GTK_BUTTONS_NONE,
469                        "Are you sure you want to apply changes?");
470        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_CANCEL, GTK_RESPONSE_NO);
471        gtk_dialog_add_button(GTK_DIALOG (confirm), GTK_STOCK_APPLY, GTK_RESPONSE_YES);
472        gtk_dialog_set_default_response(GTK_DIALOG (confirm), GTK_RESPONSE_CANCEL);
473
474        gint response = gtk_dialog_run(GTK_DIALOG(confirm));
475        gtk_widget_destroy(confirm);
476
477        if (response == GTK_RESPONSE_YES) {
478                GtkWidget* treeview = (GtkWidget*)g_object_get_data(G_OBJECT(widget), "treeview");
479                sonydb->writeTracks();
480                rebuild_tree(treeview, sonydb, true);
481        }
482}
483
484void treeview_multi_delete(
485                GtkTreeModel* model,
486                GtkTreePath* path,
487                GtkTreeIter* iter,
488                gpointer data) {
489        SonyDb* sonydb = (SonyDb*)data;
490        Song* song = NULL;
491        bool removed = false;
492        gtk_tree_model_get(model, iter, COL_SONG, &song, -1);
493        if (song) {
494                sonydb->delSong(song);
495                removed = true;
496        } else {
497                GtkTreeIter iter_album;
498                GtkTreeIter iter_title;
499                if (gtk_tree_path_get_depth(path) == 2) {
500                        if (!gtk_tree_model_iter_children(model, &iter_title, iter))
501                                return;
502                        while(true) {
503                                gtk_tree_model_get(model, &iter_title, COL_SONG, &song, -1);
504                                if (song) {
505                                        sonydb->delSong(song);
506                                        removed = true;
507                                }
508                                if (!gtk_tree_model_iter_next(model, &iter_title)) break;
509                        }
510                }
511                else
512                if (gtk_tree_path_get_depth(path) == 1) {
513                        if (!gtk_tree_model_iter_children(model, &iter_album, iter))
514                                return;
515                        while(true) {
516                                if (!gtk_tree_model_iter_children(model, &iter_title, &iter_album))
517                                        return;
518                                while(true) {
519                                        gtk_tree_model_get(model, &iter_title, COL_SONG, &song, -1);
520                                        if (song) {
521                                                sonydb->delSong(song);
522                                                removed = true;
523                                        }
524                                        if (!gtk_tree_model_iter_next(model, &iter_title)) break;
525                                }
526                                if (song) {
527                                        sonydb->delSong(song);
528                                        removed = true;
529                                }
530                                if (!gtk_tree_model_iter_next(model, &iter_album)) break;
531                        }
532                }
533        }
534        if (removed)
535                g_object_set_data(G_OBJECT(model), "deleted", (void*)"yes");
536}
537
538gboolean on_key_pressed(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
539{
540        SonyDb* sonydb = (SonyDb*)user_data;
541        GtkTreeSelection* selection;
542        GtkTreeModel* model;
543        GtkTreeIter iter;
544        if (event->keyval == GDK_F5) {
545                rebuild_tree(widget, sonydb, true);
546        }
547        else
548        if (event->keyval == GDK_Delete) {
549                GtkTreeModel* model;
550                model = (GtkTreeModel*)gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
551                g_object_set_data(G_OBJECT(model), "deleted", NULL);
552                selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
553                gtk_tree_selection_selected_foreach(selection, treeview_multi_delete, sonydb);
554                if (g_object_get_data(G_OBJECT(model), "deleted"))
555                        rebuild_tree(widget, sonydb, false);
556        }
557        return TRUE;
558}
559
560void edit_dialog(GtkWidget* widget, SonyDb* sonydb, Song* song, int edit_type)
561{
562        GtkWidget* dialog;
563        GtkWidget* table;
564        GtkWidget* label;
565        GtkWidget* artist;
566        GtkWidget* album;
567        GtkWidget* title;
568
569        dialog = gtk_dialog_new();
570        gtk_dialog_add_buttons(GTK_DIALOG(dialog),
571                        GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
572                        GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
573                        NULL);
574
575        gtk_window_set_title(GTK_WINDOW(dialog), gtk_window_get_title(GTK_WINDOW(gtk_widget_get_toplevel(widget))));
576        gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
577        gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
578
579        table = gtk_table_new(2, 3, FALSE);
580        gtk_container_set_border_width(GTK_CONTAINER(table), 6);
581        gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
582
583        label = gtk_label_new("Artist:");
584        gtk_table_attach(
585                        GTK_TABLE(table),
586                        label,
587                        0, 1,                   0, 1,
588                        GTK_FILL,               GTK_FILL,
589                        0,                      0);
590        artist = gtk_entry_new();
591        gtk_entry_set_text(GTK_ENTRY(artist), g_locale_to_utf8(song->artist, -1, NULL, NULL, NULL));
592        gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
593        gtk_label_set_mnemonic_widget(GTK_LABEL(label), artist);
594        gtk_table_attach(
595                        GTK_TABLE(table),
596                        artist,
597                        1, 2,                   0, 1,
598                        (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), GTK_FILL,
599                        0,                      0);
600
601        label = gtk_label_new("Album:");
602        gtk_table_attach(
603                        GTK_TABLE(table),
604                        label,
605                        0, 1,                   1, 2,
606                        GTK_FILL,               GTK_FILL,
607                        0,                      0);
608        album = gtk_entry_new();
609        gtk_entry_set_text(GTK_ENTRY(album), g_locale_to_utf8(song->album, -1, NULL, NULL, NULL));
610        gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
611        gtk_label_set_mnemonic_widget(GTK_LABEL(label), album);
612        gtk_table_attach(
613                        GTK_TABLE(table),
614                        album,
615                        1, 2,                   1, 2,
616                        (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), GTK_FILL,
617                        0,                      0);
618
619        label = gtk_label_new("Title:");
620        gtk_table_attach(
621                        GTK_TABLE(table),
622                        label,
623                        0, 1,                   2, 3,
624                        GTK_FILL,               GTK_FILL,
625                        0,                      0);
626        title = gtk_entry_new();
627        gtk_entry_set_text(GTK_ENTRY(title), g_locale_to_utf8(song->title, -1, NULL, NULL, NULL));
628        gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
629        gtk_label_set_mnemonic_widget(GTK_LABEL(label), title);
630        gtk_table_attach(
631                        GTK_TABLE(table),
632                        title,
633                        1, 2,                   2, 3,
634                        (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), GTK_FILL,
635                        0,                      0);
636        gtk_window_set_transient_for(
637                        GTK_WINDOW(dialog),
638                        GTK_WINDOW(gtk_widget_get_toplevel(widget)));
639
640        gtk_widget_show_all(dialog);
641        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
642                gchar* artist_text = (gchar*)g_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(artist)), -1, NULL, NULL, NULL);
643                gchar* album_text = (gchar*)g_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(album)), -1, NULL, NULL, NULL);
644                gchar* title_text = (gchar*)g_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(title)), -1, NULL, NULL, NULL);
645                free(song->artist);
646                free(song->album);
647                free(song->title);
648                song->artist = strdup(artist_text);
649                song->album = strdup(album_text);
650                song->title = strdup(title_text);
651                sonydb->updSong(song);
652                rebuild_tree(widget, sonydb, false);
653        }
654
655        gtk_widget_destroy(dialog);
656}
657
658void on_row_activated(
659                GtkTreeView* treeview,
660                GtkTreePath* path,
661                GtkTreeViewColumn* column,
662                gpointer user_data)
663{
664        SonyDb* sonydb = (SonyDb*)user_data;
665        GtkTreeIter iter;
666        Song* song;
667
668        GtkTreeModel* model = (GtkTreeModel*)gtk_tree_view_get_model(treeview);
669        gtk_tree_model_get_iter(model, &iter, path);
670        gtk_tree_model_get(model, &iter, COL_SONG, &song, -1);
671        if (song) {
672                edit_dialog(GTK_WIDGET(treeview), sonydb, song, EDIT_TYPE_TITLE);
673        }
674}
675
676void on_drag_data_received(
677                GtkWidget* widget,
678                GdkDragContext* drag_context,
679                gint x,
680                gint y,
681                GtkSelectionData* data,
682                guint info,
683                guint time,
684                gpointer user_data)
685{
686        SonyDb* sonydb = (SonyDb*)user_data;
687        gchar* uri_list = (gchar*)data->data;
688        gchar** uris = g_strsplit(uri_list, "\r\n", 255);
689        for(; *uris; uris++) {
690                gchar* file_utf = g_filename_from_uri(g_strchomp(*uris), NULL, NULL);
691                if (!file_utf) continue;
692                gchar* file_loc = g_locale_from_utf8(file_utf, -1, NULL, NULL, NULL);
693                std::string file = file_loc;
694                g_free(file_utf);
695                g_free(file_loc);
696
697                ID3Tag* tag = ID3Tag_New();
698                if (ID3Tag_LinkWithFlags(tag, file.c_str(), ID3TT_ID3V2) == 0) {
699                        ID3Tag_Delete(tag);
700                        continue;
701                }
702                Song* song = new Song;
703                memset(song, 0, sizeof(Song));
704
705                song->album=strdup(get_tag(tag, ID3FID_ALBUM));
706                song->artist=strdup(get_tag(tag, ID3FID_LEADARTIST));
707                song->title=strdup(get_tag(tag, ID3FID_TITLE));
708                song->genre=strdup(get_genre(get_tag(tag, ID3FID_CONTENTTYPE)));
709                song->track_nr=atol(get_tag(tag, ID3FID_TRACKNUM));
710                song->filename = strdup(file.c_str());
711                song->year=atol(get_tag(tag, ID3FID_RELEASETIME));
712                song->songlen=atol(get_tag(tag, ID3FID_SONGLEN))/1000;
713                song->wAlbum = 0; //(utf16char*)wcsdup(tag.getAlbum());
714                song->wArtist = 0; //(utf16char*)wcsdup(tag.getArtist());
715                song->wGenre = 0; //(utf16char*)wcsdup(string2wstring(song->genre).c_str());
716                song->wTitle = 0; //(utf16char*)wcsdup(tag.getTitle());
717                song->statusOfSong = ADD_TO_DEVICE;
718                print_song(song);
719                sonydb->addSong(song);
720                ID3Tag_Delete(tag);
721                rebuild_tree(widget, sonydb, false);
722        }
723}
724
725void gui(int argc, char* argv[])
726{
727        GtkWidget* window;
728        GtkWidget* treeview;
729        GtkWidget* swin;
730        GtkWidget* button;
731        GtkTreeSelection* selection;
732        GtkTreeStore* store;
733        GtkCellRenderer *renderer;
734        GtkTreeViewColumn *column;
735        GtkWidget* vbox;
736        GtkWidget* hbox;
737        GtkTargetList* targetlist;
738        GtkTargetEntry drag_types[] = {
739        {"text/uri-list", 0, 1}
740        };
741        gint n_drag_types = sizeof (drag_types) / sizeof (drag_types [0]);
742        bool detected = false;
743        SonyDb sonydb;
744
745        gtk_init(&argc, &argv);
746
747        char* playerPath = getenv("SONYDB_PLAYERPATH");
748        if (playerPath != NULL) {
749                if (!sonydb.detectPlayer(playerPath)) {
750                        argc = 0;
751                }
752        } else {
753                if (!sonydb.detectPlayer()) {
754                        argc = 0;
755                }
756        }
757
758        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
759        gtk_window_set_title(GTK_WINDOW(window), "SonyDb");
760        g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);
761
762        vbox = gtk_vbox_new(FALSE, 6);
763        gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
764        gtk_container_add(GTK_CONTAINER(window), vbox);
765
766        store = gtk_tree_store_new(COL_MAX,
767                        GDK_TYPE_PIXBUF,
768                        GTK_TYPE_STRING,
769                        GTK_TYPE_POINTER);
770        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
771        gtk_drag_dest_set(
772                        treeview,
773                        GTK_DEST_DEFAULT_ALL,
774                        drag_types,
775                        n_drag_types,
776                        GDK_ACTION_COPY);
777        g_signal_connect(G_OBJECT(treeview), "drag-data-received", G_CALLBACK(on_drag_data_received), &sonydb);
778        g_signal_connect(G_OBJECT(treeview), "key-press-event", G_CALLBACK(on_key_pressed), &sonydb);
779        g_signal_connect(G_OBJECT(treeview), "row_activated", G_CALLBACK(on_row_activated), &sonydb);
780        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
781        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_TEXT);
782        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
783        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
784        gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
785
786        column = gtk_tree_view_column_new();
787
788        // artist
789    renderer = gtk_cell_renderer_pixbuf_new();
790        g_object_set(renderer, "xalign", 0.0, NULL);
791        gtk_tree_view_column_pack_start(column, renderer, FALSE);
792        gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", COL_ICON);
793    renderer = gtk_cell_renderer_text_new();
794        g_object_set(renderer, "xalign", 0.0, NULL);
795        g_object_set(renderer, "weight", PANGO_WEIGHT_BOLD, NULL);
796        gtk_tree_view_column_pack_start(column, renderer, FALSE);
797        gtk_tree_view_column_add_attribute(column, renderer, "text", COL_TEXT);
798
799    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
800
801        swin = gtk_scrolled_window_new(NULL, NULL);
802        gtk_scrolled_window_set_policy(
803                        GTK_SCROLLED_WINDOW(swin),
804                        GTK_POLICY_AUTOMATIC,
805                        GTK_POLICY_AUTOMATIC);
806        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin), GTK_SHADOW_IN);
807        gtk_container_add(GTK_CONTAINER(swin), treeview);
808
809        gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
810
811        hbox = gtk_hbox_new(FALSE, 6);
812        gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
813        gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
814
815        button = gtk_button_new_with_label("_Update");
816        gtk_label_set_use_underline(GTK_LABEL(GTK_BIN(button)->child), TRUE);
817        g_object_set_data(G_OBJECT(button), "treeview", treeview);
818        g_object_set_data(G_OBJECT(treeview), "update", button);
819        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_update_clicked), &sonydb);
820        gtk_container_add(GTK_CONTAINER(hbox), button);
821
822        button = gtk_button_new_with_label("_Apply");
823        gtk_label_set_use_underline(GTK_LABEL(GTK_BIN(button)->child), TRUE);
824        g_object_set_data(G_OBJECT(button), "treeview", treeview);
825        g_object_set_data(G_OBJECT(treeview), "apply", button);
826        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_apply_clicked), &sonydb);
827        gtk_container_add(GTK_CONTAINER(hbox), button);
828
829        button = gtk_button_new_with_label("C_lean");
830        gtk_label_set_use_underline(GTK_LABEL(GTK_BIN(button)->child), TRUE);
831        g_object_set_data(G_OBJECT(button), "treeview", treeview);
832        g_object_set_data(G_OBJECT(treeview), "clean", button);
833        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_clean_clicked), &sonydb);
834        gtk_container_add(GTK_CONTAINER(hbox), button);
835
836        button = gtk_button_new_with_label("_Close");
837        gtk_label_set_use_underline(GTK_LABEL(GTK_BIN(button)->child), TRUE);
838        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gtk_main_quit), NULL);
839        gtk_container_add(GTK_CONTAINER(hbox), button);
840
841        gtk_widget_set_size_request(window, 300, 200);
842        gtk_widget_queue_resize(window);
843        gtk_widget_show_all(window);
844
845        if (detected) {
846                rebuild_tree(treeview, &sonydb, true);
847        } else {
848                GtkWidget* error;
849                error  = gtk_message_dialog_new(
850                        GTK_WINDOW(window),
851                        (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
852                        GTK_MESSAGE_ERROR,
853                        GTK_BUTTONS_OK,
854                        "Can't detect devices!");
855                gtk_window_set_title(GTK_WINDOW(error), gtk_window_get_title(GTK_WINDOW(window)));
856                gint response = gtk_dialog_run(GTK_DIALOG(error));
857                gtk_widget_destroy(error);
858                return;
859        }
860
861        gtk_main();
862}
863#endif
864
865int main(int argc, char* argv[])
866{
867#ifdef GUI
868        gui(argc, argv);
869#else
870        setlocale(LC_CTYPE, "");
871        SonyDb sonydb;
872
873        char* playerPath = getenv("SONYDB_PLAYERPATH");
874        if (playerPath != NULL) {
875                if (!sonydb.detectPlayer(playerPath)) {
876                        argc = 0;
877                }
878        } else {
879                if (!sonydb.detectPlayer()) {
880                        argc = 0;
881                }
882        }
883
884        if (argc == 2 && !strcmp(argv[1], "songs")) {
885                vector<Song*> songs;
886                vector<Song*>::iterator itsongs;
887                sonydb.readAllTracks();
888                songs = sonydb.getSongs();
889                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
890                        printf("%04d,%s,%s,%s\n",
891                                        (*itsongs)->sonyDbOrder,
892                                        (*itsongs)->artist,
893                                        (*itsongs)->album,
894                                        (*itsongs)->title
895                                        );
896                        deleteSongPtr(*itsongs);
897                }
898        }
899        else
900        if (argc == 3 && !strcmp(argv[1], "songs")) {
901                vector<Song*> songs;
902                vector<Song*>::iterator itsongs;
903                sonydb.readAllTracks();
904                songs = sonydb.getSongs();
905                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
906                        if ((*itsongs)->sonyDbOrder == atol(argv[2])) {
907                                printf("songs(%04d): %s,%s,%s\n\tencoding=%s\n\tfilename=%s\n\tgenre=%s\n\tsonglen=%d\n\ttrack_nr=%d\n\tyear=%d\n",
908                                                (*itsongs)->sonyDbOrder,
909                                                (*itsongs)->artist,
910                                                (*itsongs)->album,
911                                                (*itsongs)->title,
912                                                (*itsongs)->encoding,
913                                                (*itsongs)->filename,
914                                                (*itsongs)->genre,
915                                                (*itsongs)->songlen,
916                                                (*itsongs)->track_nr,
917                                                (*itsongs)->year
918                                                );
919                        }
920                        deleteSongPtr(*itsongs);
921                }
922        }
923        else
924        if (argc == 3 && !strcmp(argv[1], "songsdel")) {
925                vector<Song*> songs;
926                vector<Song*>::iterator itsongs;
927                sonydb.readAllTracks();
928                songs = sonydb.getSongs();
929                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
930                        if ((*itsongs)->sonyDbOrder == atol(argv[2]))
931                                sonydb.delSong(*itsongs);
932                        deleteSongPtr(*itsongs);
933                }
934                sonydb.writeTracks();
935        }
936        else
937        if (argc >= 3 && !strcmp(argv[1], "songsadd")) {
938                vector<Song*> songs;
939                sonydb.readAllTracks();
940                songs = sonydb.getSongs();
941
942                ID3Tag* tag;
943
944                std::string title;
945                std::string artist;
946                std::string album;
947                std::string genre;
948                std::vector<std::string> files;
949                int track_nr = 0;
950                int n;
951                for(n = 2; n < argc; n++) {
952                        if (!strcmp(argv[n], "-title"))
953                                title = argv[++n];
954                        else
955                        if (!strcmp(argv[n], "-artist"))
956                                artist = argv[++n];
957                        else
958                        if (!strcmp(argv[n], "-album"))
959                                album = argv[++n];
960                        else
961                        if (!strcmp(argv[n], "-genre"))
962                                genre = argv[++n];
963                        else
964                        if (!strcmp(argv[n], "-track_nr"))
965                                track_nr = atol(argv[++n]);
966                        else
967                                break;
968                }
969
970                for(; n < argc; n++) {
971                        tag = ID3Tag_New();
972                        ID3Tag_Link(tag, argv[n]);
973                        Song* song = new Song;
974                        memset(song, 0, sizeof(Song));
975
976                        if (!album.size())
977                                song->album=strdup(get_tag(tag, ID3FID_ALBUM));
978                        else
979                                song->album=strdup(album.c_str());
980                        if (!artist.size())
981                                song->artist=strdup(get_tag(tag, ID3FID_LEADARTIST));
982                        else
983                                song->artist=strdup(artist.c_str());
984                        if (!title.size())
985                                song->title=strdup(get_tag(tag, ID3FID_TITLE));
986                        else
987                                song->title=strdup(title.c_str());
988                        if (!genre.size())
989                                song->genre=strdup(get_genre(get_tag(tag, ID3FID_CONTENTTYPE)));
990                        else
991                                song->genre=strdup(genre.c_str());
992                        if (track_nr < 1)
993                                song->track_nr=atol(get_tag(tag, ID3FID_TRACKNUM));
994                        else
995                                song->track_nr=track_nr;
996                        song->filename = strdup(argv[n]);
997                        song->year=atol(get_tag(tag, ID3FID_RELEASETIME));
998                        song->songlen=atol(get_tag(tag, ID3FID_SONGLEN))/1000;
999                        song->wAlbum = 0; //(utf16char*)wcsdup(tag.getAlbum());
1000                        song->wArtist = 0; //(utf16char*)wcsdup(tag.getArtist());
1001                        song->wGenre = 0; //(utf16char*)wcsdup(string2wstring(song->genre).c_str());
1002                        song->wTitle = 0; //(utf16char*)wcsdup(tag.getTitle());
1003                        song->statusOfSong = ADD_TO_DEVICE;
1004                        sonydb.addSong(song);
1005                        ID3Tag_Delete(tag);
1006                }
1007                sonydb.writeTracks();
1008        }
1009        else
1010        if (argc == 3 && !strcmp(argv[1], "songschk")) {
1011                vector<Song*> songs;
1012                sonydb.readAllTracks();
1013                songs = sonydb.getSongs();
1014
1015                ID3Tag* tag;
1016
1017                tag = ID3Tag_New();
1018                ID3Tag_Link(tag, argv[2]);
1019                Song* song = new Song;
1020                memset(song, 0, sizeof(Song));
1021
1022                song->album=strdup(get_tag(tag, ID3FID_ALBUM));
1023                song->artist=strdup(get_tag(tag, ID3FID_LEADARTIST));
1024                song->title=strdup(get_tag(tag, ID3FID_TITLE));
1025                song->genre=strdup(get_genre(get_tag(tag, ID3FID_CONTENTTYPE)));
1026                song->filename = strdup(argv[2]);
1027                song->track_nr=atol(get_tag(tag, ID3FID_TRACKNUM));
1028                song->year=atol(get_tag(tag, ID3FID_RELEASETIME));
1029                song->songlen=atol(get_tag(tag, ID3FID_SONGLEN))/1000;
1030                song->wAlbum = 0; //(utf16char*)wcsdup(tag.getAlbum());
1031                song->wArtist = 0; //(utf16char*)wcsdup(tag.getArtist());
1032                song->wGenre = 0; //(utf16char*)wcsdup(string2wstring(song->genre).c_str());
1033                song->wTitle = 0; //(utf16char*)wcsdup(tag.getTitle());
1034                song->statusOfSong = ADD_TO_DEVICE;
1035                printf("songs(%04d): %s,%s,%s\n\tencoding=%s\n\tfilename=%s\n\tgenre=%s\n\tsonglen=%d\n\ttrack_nr=%d\n\tyear=%d\n",
1036                                song->sonyDbOrder,
1037                                song->artist,
1038                                song->album,
1039                                song->title,
1040                                song->encoding,
1041                                song->filename,
1042                                song->genre,
1043                                song->songlen,
1044                                song->track_nr,
1045                                song->year
1046                                );
1047        }
1048        else
1049        if (argc == 2 && !strcmp(argv[1], "plist")) {
1050                vector<Playlist*> plist;
1051                vector<Playlist*>::iterator itplist;
1052                sonydb.readAllPlaylist();
1053                plist = sonydb.getPlaylist();
1054                for(itplist = plist.begin(); itplist != plist.end(); itplist++) {
1055                        printf("%04d,%s\n",
1056                                        (*itplist)->index,
1057                                        (*itplist)->name
1058                                        );
1059                }
1060        }
1061        else
1062        if (argc == 3 && !strcmp(argv[1], "plist")) {
1063                vector<Playlist*> plist;
1064                vector<Song*> songs;
1065                vector<Playlist*>::iterator itplist;
1066                sonydb.readAllTracks();
1067                sonydb.readAllPlaylist();
1068                plist = sonydb.getPlaylist();
1069                for(itplist = plist.begin(); itplist != plist.end(); itplist++) {
1070                        if ((*itplist)->index == atol(argv[2])) {
1071                                printf("playlist(%04d): %s\n",
1072                                                (*itplist)->index,
1073                                                (*itplist)->name
1074                                                );
1075                                songs = sonydb.getSongsInPlaylist((*itplist)->index);
1076                                vector<Song*>::iterator itsongs;
1077                                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
1078                                        printf("%04d,%s,%s,%s\n",
1079                                                        (*itsongs)->sonyDbOrder,
1080                                                        (*itsongs)->artist,
1081                                                        (*itsongs)->album,
1082                                                        (*itsongs)->title
1083                                                        );
1084                                        deleteSongPtr(*itsongs);
1085                                }
1086                        }
1087                }
1088        }
1089        else
1090        if (argc >= 3 && !strcmp(argv[1], "plistadd")) {
1091                vector<Song*> songs;
1092                vector<Song*>::iterator itsongs;
1093                vector<Playlist*> plist;
1094
1095                sonydb.readAllTracks();
1096                sonydb.readAllPlaylist();
1097                songs = sonydb.getSongs();
1098                plist = sonydb.getPlaylist();
1099
1100                Playlist* newplist = new Playlist;
1101                newplist->name = strdup(argv[2]);
1102                newplist->index = plist.size() + 1;
1103                for(itsongs = songs.begin(); itsongs != songs.end(); itsongs++) {
1104                        for(int n = 2; n < argc; n++) {
1105                                if (atol(argv[n]) == (*itsongs)->sonyDbOrder)
1106                                        newplist->songs.push_back(*itsongs);
1107                        }
1108                }
1109                sonydb.addPlaylist(newplist);
1110                sonydb.writeTracks();
1111        }
1112        else
1113        if (argc == 3 && !strcmp(argv[1], "plistdel")) {
1114                sonydb.readAllTracks();