1 /*
2 *  qm_player.cpp
3 *  QUIMUP main player window
4 *  © 2008-2018 Johan Spee
5 *
6 *  This file is part of Quimup
7 *
8 *  QUIMUP is free software: you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation, either version 3 of the License, or
11 *  (at your option) any later version.
12 *
13 *  QUIMUP is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program. If not, see http://www.gnu.org/licenses/.
20 */
21 
22 #include "qm_player.h"
23 
qm_player()24 qm_player::qm_player()
25 {
26     if (objectName().isEmpty())
27         setObjectName("player");
28 
29     this->setAcceptDrops(true);
30 
31     setupUI();
32 
33     init_vars(); // incl. config
34 
35     retranslateUI();
36 
37     if (config->start_minimized)
38         this->showMinimized();
39     else
40         this->show();
41 
42     window_W_max = this->width();
43     window_H_max = this->height();
44 
45     if (config->player_maxmode)
46     {
47         window_H = window_H_max;
48         setFixedSize(window_W_max, window_H_max);
49     }
50     else
51     { // minimode
52         window_H = 106;
53         center_widget->hide();
54         setFixedSize(window_W_max, window_H);
55         config->player_maxmode = false;
56     }
57 
58     QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
59     setSizePolicy(sizePolicy);
60 
61     this->setAttribute(Qt::WA_QuitOnClose, false);
62     // trigger window-manager update: hide & show
63     this->hide();
64 
65     if (config->start_minimized)
66         this->showMinimized();
67     else
68         this->show();
69 
70     this->activateWindow();
71 
72     mpdCom->configure();
73 
74     // connect and set status
75     if (config->auto_connect)
76     {
77         printf ("Auto-connecting, as configured\n");
78 
79         if (!mpdCom->mpd_connect())
80         {
81             printf ("Failed to connect to MPD\n");
82             // mpdCom->show_messagebox(tr("Could not connect to MPD!"), tr("Please check the 'Connect' tab in the 'Settings' window."));
83         }
84     }
85     else
86     {
87         printf ("NOT Connecting, as configured\n");
88         on_connect_sgnl(false);
89     }
90 }
91 
92 // from mpdCom
on_connect_sgnl(bool isconnected)93 void qm_player::on_connect_sgnl(bool isconnected)
94 {
95     if (isconnected)
96     {
97         b_mpd_connected = true;
98         settings_window->set_connected(mpdCom, true);
99         browser_window->set_connected(mpdCom, true);
100         browser_window->plist_view->set_connected(mpdCom, true);
101         browser_window->lib_view->set_connected(mpdCom, true);
102         if (b_use_trayicon)
103             the_trayicon->set_connected(mpdCom, true);
104         set_status(0, " ");
105         if(config->mpd_musicpath_status == 1)
106             context_menu->setEnabled(true);
107         else
108             context_menu->setEnabled(false);
109     }
110     else
111     {
112         b_mpd_connected = false;
113         settings_window->set_connected(mpdCom, false);
114         browser_window->set_connected(mpdCom, false);
115         browser_window->plist_view->set_connected(mpdCom, false);
116         browser_window->lib_view->set_connected(mpdCom, false);
117         if (b_use_trayicon)
118             the_trayicon->set_connected(mpdCom, false);
119         set_status(-1, tr("Not connected") );
120         context_menu->setEnabled(false);
121     }
122 }
123 
124 
setupUI()125 void qm_player::setupUI()
126 {
127     if (objectName().isEmpty())
128         setObjectName(QString::fromUtf8("qm_player"));
129 
130     QPixmap qpx;
131     qpx = QPixmap(":/mn_icon.png");
132     setWindowIcon(qpx);
133     setWindowTitle("Quimup");
134 
135     main_widget = new QWidget();
136     vbox_all = new QVBoxLayout(main_widget);
137     setCentralWidget(main_widget);
138     vbox_all->setMargin(6);
139     vbox_all->setSpacing(4);
140 
141     main_display = new QLabel(); // used as QFrame
142     main_display->setFixedSize(324,50);
143     main_display->setFrameShape(QFrame::Panel);
144     main_display->setFrameShadow(QFrame::Sunken);
145 
146     lb_extension = new QLabel(main_display);
147     lb_extension->setGeometry(QRect(10, 28, 50, 20));
148     lb_extension->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
149     lb_extension->setWordWrap(false);
150 
151     lb_time = new clickLabel(main_display);
152     lb_time->setGeometry(QRect(200, 28, 114, 20));
153     lb_time->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
154     lb_time->setWordWrap(false);
155     lb_time->setTextFormat(Qt::RichText);
156 
157     title_scroller = new qm_Scroller(main_display);
158     title_scroller->setGeometry(QRect(2, 2, 320, 24));
159     title_scroller->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);
160 
161     lb_kbps = new QLabel(main_display);
162     lb_kbps->setGeometry(QRect(66, 28, 64, 20));
163     lb_kbps->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
164     lb_kbps->setWordWrap(false);
165 
166     lb_kHz = new QLabel(main_display);
167     lb_kHz->setGeometry(QRect(140, 28, 64, 20));
168     lb_kHz->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
169     lb_kHz->setWordWrap(false);
170 
171     vbox_all->addWidget(main_display);
172 
173     ds_progress = new qm_clickprogressbar();
174     ds_progress->setOrientation (Qt::Horizontal);
175     ds_progress->setFixedSize(324,8);
176     ds_progress->setStyleSheet(
177         "QSlider::groove:horizontal {"
178         "margin: 0 0 0 0;"
179         "border: 1px solid #aaa;"
180         "background: transparent;"
181         "height: 3px;"
182         "border-radius: 2px;}"
183         "QSlider::sub-page:horizontal {"
184         "border-image: url(:/groove_bg_noconn.png); }");
185     ds_progress->setMinimum(0);
186     vbox_all->addWidget(ds_progress);
187 
188     spacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding);
189     vbox_all->addItem(spacer);
190 
191     center_widget = new QLabel();
192     center_widget->setFixedSize(324, 200);
193 
194     hbox_center = new QHBoxLayout(center_widget);
195     hbox_center->setMargin(0);
196     hbox_center->setSpacing(2);
197     hbox_center->setAlignment(Qt::AlignLeft|Qt::AlignTop);
198 
199     lb_albumart = new QLabel();
200     lb_albumart->setFixedSize(200, 200);
201     lb_albumart->setScaledContents(false);
202     lb_albumart->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);
203     hbox_center->addWidget(lb_albumart);
204     vbox_cright = new QVBoxLayout();
205     vbox_cright->setMargin(0);
206     vbox_cright->setSpacing(0);
207     vbox_cright->setAlignment(Qt::AlignLeft|Qt::AlignTop);
208     vbox_cright->setGeometry(QRect(0, 0, 122, 200)); // lb_album + lb_comment must fit
209     lb_album = new QLabel();
210     lb_album->setWordWrap(true);
211     lb_album->setMargin(2);
212     lb_album->setMinimumSize(122, 4);
213     lb_album->setTextFormat(Qt::RichText);
214     lb_album->setAlignment(Qt::AlignLeft|Qt::AlignTop);
215     vbox_cright->addWidget(lb_album);
216     lb_comment = new QLabel();
217     lb_comment->setMargin(2);
218     lb_comment->setWordWrap(true);
219     //lb_comment->setTextFormat(Qt::RichText);
220     lb_comment->setAlignment(Qt::AlignLeft|Qt::AlignTop);
221     vbox_cright->addWidget(lb_comment);
222     hbox_center->addLayout(vbox_cright);
223     vbox_all->addWidget(center_widget);
224 
225     hbox_bottom = new QHBoxLayout();
226     hbox_bottom->setMargin(0);
227     hbox_bottom->setSpacing(4);
228     bt_prev = new QPushButton();
229     bt_prev->setFixedSize(34,28);
230     bt_prev->setIcon(QIcon(":/mn_prev.png"));
231     hbox_bottom->addWidget(bt_prev);
232     bt_stop = new QPushButton();
233     bt_stop->setFixedSize(34,28);
234     bt_stop->setIcon(QIcon(":/mn_stop.png"));
235     hbox_bottom->addWidget(bt_stop);
236     bt_playpause = new QPushButton();
237     bt_playpause->setFixedSize(34,28);
238     bt_playpause->setIcon(QIcon(":/mn_play.png"));
239     bt_playpause->setDefault(false);
240     hbox_bottom->addWidget(bt_playpause);
241     bt_next = new QPushButton();
242     bt_next->setFixedSize(34,28);
243     bt_next->setIcon(QIcon(":/mn_next.png"));
244     hbox_bottom->addWidget(bt_next);
245     bt_browser = new QPushButton();
246     bt_browser->setFixedSize(34,28);
247     bt_browser->setIcon(QIcon(":/mn_playlist.png"));
248     hbox_bottom->addWidget(bt_browser);
249     vol_slider = new QSlider(Qt::Horizontal);
250     vol_slider->setRange(0,100);
251     vol_slider->setFixedSize(58,28);
252     vol_slider->setStyleSheet(
253         "QSlider::groove:horizontal {"
254         "margin: 1px 0 1px 0;"
255         "border: 1px solid #aaa;"
256         "background: transparent;"
257         "height: 3px;"
258         "border-radius: 2px; }"
259         "QSlider::handle:horizontal {"
260         "image: url(:/vol_handle.png);"
261         "height: 15px;"
262         "width: 6px;"
263         "margin: -4px 0;}");
264     hbox_bottom->addWidget(vol_slider);
265     bt_sizer = new QPushButton();
266     bt_sizer->setFixedSize(34,28);
267     bt_sizer->setIcon(QIcon(":/mn_sizer.png"));
268     hbox_bottom->addWidget(bt_sizer);
269     bt_setts = new QPushButton();
270     bt_setts->setFixedSize(34,28);
271     bt_setts->setIcon(QIcon(":/mn_config.png"));
272     hbox_bottom->addWidget(bt_setts);
273     vbox_all->addLayout(hbox_bottom);
274 
275     // buttonmapper
276     button_mapper = new QSignalMapper();
277 
278     button_mapper->setMapping( bt_playpause, ID_play );
279     QObject::connect(bt_playpause, SIGNAL(clicked()), button_mapper, SLOT(map()));
280 
281     button_mapper->setMapping( bt_stop, ID_stop );
282     QObject::connect(bt_stop, SIGNAL(clicked()), button_mapper, SLOT(map()));
283 
284     button_mapper->setMapping( bt_next, ID_next );
285     QObject::connect(bt_next, SIGNAL(clicked()), button_mapper, SLOT(map()));
286 
287     button_mapper->setMapping( bt_prev, ID_prev );
288     QObject::connect(bt_prev, SIGNAL(clicked()), button_mapper, SLOT(map()));
289 
290     button_mapper->setMapping( bt_browser, ID_plst );
291     QObject::connect(bt_browser, SIGNAL(clicked()), button_mapper, SLOT(map()));
292 
293     button_mapper->setMapping( bt_setts, ID_sets );
294     QObject::connect(bt_setts, SIGNAL(clicked()), button_mapper, SLOT(map()));
295 
296     button_mapper->setMapping(lb_time, ID_time );
297     QObject::connect(lb_time, SIGNAL(clicked()), button_mapper, SLOT(map()));
298 
299     button_mapper->setMapping( bt_sizer, ID_mmax );
300     QObject::connect(bt_sizer, SIGNAL(clicked()), button_mapper, SLOT(map()));
301 
302     QObject::connect( button_mapper, SIGNAL( mapped(int) ), this, SLOT( on_signal(int) ) );
303     // end buttonmapper
304 
305     QObject::connect(ds_progress, SIGNAL(pressed(QMouseEvent*)), this, SLOT(lock_progress(QMouseEvent*)));
306 
307     QObject::connect(ds_progress, SIGNAL(clicked()), this, SLOT(unlock_progress()));
308 
309     minimizer = new QTimer();
310     QObject::connect(minimizer, SIGNAL(timeout()), this, SLOT(minimice()));
311     maximizer = new QTimer();
312     QObject::connect(maximizer, SIGNAL(timeout()), this, SLOT(lock_progress()));
313 
314     this->setContextMenuPolicy(Qt::CustomContextMenu);
315     QObject::connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_contextmenu()) );
316 
317     // CONTEXT MENU
318     context_menu = new QMenu();
319     a_menuheader = new QAction(context_menu);
320     a_menuheader->setText(tr("Folder actions:"));
321     QFont font;
322     font.setPointSize(8);
323     a_menuheader->setFont(font);
324     context_menu->addAction(a_menuheader);
325     a_menuheader->setEnabled(false);
326 
327     a_opendir = new QAction(context_menu);
328     a_opendir->setText(tr("File Manager"));
329     a_opendir->setIcon(QIcon(":/menu_dir.png"));
330     QObject::connect( a_opendir, SIGNAL( triggered() ), this, SLOT( open_directory() ) );
331     context_menu->addAction(a_opendir);
332 
333     a_edittags = new QAction(context_menu);
334     a_edittags->setText(tr("Tag Editor"));
335     a_edittags->setIcon(QIcon(":/menu_edit.png"));
336     QObject::connect( a_edittags, SIGNAL( triggered() ), this, SLOT( edit_tags() ) );
337     context_menu->addAction(a_edittags);
338 
339     a_openaart = new QAction(context_menu);
340     a_openaart->setText(tr("Image Viewer"));
341     a_openaart->setIcon(QIcon(":/menu_view.png"));
342     QObject::connect( a_openaart, SIGNAL( triggered() ), this, SLOT( show_albumart() ) );
343     context_menu->addAction(a_openaart);
344     context_menu->addSeparator();
345 
346     a_loadtags = new QAction(context_menu);
347     a_loadtags->setText(tr("Rescan tags"));
348     a_loadtags->setIcon(QIcon(":/menu_load.png"));
349     QObject::connect( a_loadtags, SIGNAL( triggered() ), this, SLOT( reload_tags() ) );
350     context_menu->addAction(a_loadtags);
351 
352     QObject::connect(vol_slider, SIGNAL(valueChanged(int)), this, SLOT(on_volumedial(int)));
353 }
354 
355 
on_volumedial(int vol)356 void qm_player::on_volumedial(int vol)
357 {
358     if (b_mpd_sets_volume || !b_mpd_connected)
359         return;
360 
361     if (vol != current_volume)
362     {
363         current_volume = vol;
364         mpdCom->set_volume(vol);
365         if (config->show_tooltips)
366             vol_slider->setToolTip("Volume " + QString::number(vol) + " %");
367     }
368 }
369 
370 
minimice()371 void qm_player::minimice()
372 {
373     // fade the album art first
374     if (b_minmax_xfade)
375     {
376         alphacycler -= 6;
377         if (alphacycler < 0)
378             alphacycler = 0;
379 
380         int a = alphacycler;
381         QImage xfade = img_xfade_input;
382         for ( int j = 0; j < albumart_H; j++ )
383         {
384             QRgb *px = (reinterpret_cast<QRgb *>(xfade.scanLine(j)) );
385             for ( int k = 0; k < albumart_W; k++ )
386             {
387                 uchar r = uchar( ( int(qRed(*px))   * a  +  cR * (255 - a)) / 255 );
388                 uchar g = uchar( ( int(qGreen(*px)) * a  +  cG * (255 - a)) / 255 );
389                 uchar b = uchar( ( int(qBlue(*px))  * a  +  cB * (255 - a)) / 255 );
390                 *px = qRgba( r, g, b, 255);
391                 px++;
392             }
393         }
394 
395         pxb_xfading = QPixmap::fromImage(xfade);
396 
397         lb_albumart->setPixmap(pxb_xfading);
398 
399         if (alphacycler == 0)
400         {
401             center_widget->hide();
402             b_minmax_busy = false;
403             b_minmax_xfade = false;
404         }
405         return;
406     }
407 
408     window_H -= 16;
409     if (window_H >= 106)
410     {
411         setFixedSize(window_W_max, window_H);
412     }
413     else
414     {
415         setFixedSize(window_W_max, 106);
416         minimizer->stop();
417     }
418 }
419 
420 
init_vars()421 void qm_player::init_vars()
422 {
423     browser_window = new qm_browser();
424     QObject::connect(browser_window, SIGNAL(sgnl_keypressed(QKeyEvent*)), this, SLOT(on_browser_keypress(QKeyEvent*)));
425 
426     settings_window = new qm_settings();
427     QObject::connect(settings_window, SIGNAL(sgnl_fonts()), this, SLOT(set_fonts()));
428     QObject::connect(settings_window, SIGNAL(sgnl_colors()), this, SLOT(set_colors()));
429     QObject::connect(settings_window, SIGNAL(sgnl_markplayed()), browser_window->plist_view, SLOT(set_markplayed()));
430     QObject::connect(settings_window, SIGNAL(sgnl_plist_auto_cols()), browser_window->plist_view, SLOT(set_auto_columns()));
431     QObject::connect(settings_window, SIGNAL(sgnl_lib_auto_cols()), browser_window->lib_view, SLOT(set_auto_columns()));
432 
433     mpdCom = new qm_mpdCom(); // before config and current_songinfo!
434     QObject::connect( mpdCom, SIGNAL( sgnl_new_song()), this, SLOT( on_new_song()));
435     QObject::connect( mpdCom, SIGNAL( sgnl_status_info(mpd_status *)), this, SLOT( on_new_status(mpd_status *)));
436     QObject::connect( mpdCom, SIGNAL( sgnl_connected (bool)), this, SLOT( on_connect_sgnl(bool)));
437     QObject::connect( mpdCom, SIGNAL( sgnl_status(int, QString)), this, SLOT( set_status(int, QString)));
438 
439     config = new qm_config(); // constructor loads values
440     mpdCom->set_config(config);
441     settings_window->set_config(config);
442     browser_window->set_config(config);
443     browser_window->plist_view->set_config(config);
444     browser_window->lib_view->set_config(config);
445 
446     if (config->version != "1.4.4")
447     {
448         config->version = "1.4.4";
449         QMessageBox msgBox;
450         msgBox.setWindowTitle("Quimup");
451         msgBox.setIcon(QMessageBox::Information);
452         msgBox.setText("<b>" + tr("Welcome to Quimup") + " " + config->version + "</b>");
453 
454         QString message = tr("Note that Quimup must be able to access MPD's music directory to find album-art and use external programs.")
455         + "\n\n"
456         + tr("Files can be added directly from your file manager (drag & drop or 'open with'), but only if you connect to MPD using a socket.")
457         + "\n\n"
458         + tr("For more details see the tips in the 'about' tab of the settings window.")
459         + "\n\n"
460         + tr("This message will not be shown again.");
461 
462         msgBox.setInformativeText(message);
463         msgBox.exec();
464     }
465 
466     setWindowTitle("Quimup " + config->version);
467 
468     current_songinfo = new qm_songInfo;
469     mpdCom->set_sInfo(current_songinfo);
470 
471     kbps_count_down = 0;
472     current_status = -99; // allow all
473     current_volume = 0;
474     current_type = TP_NOSONG;
475     current_songnr = -1;
476     if (config->show_tooltips)
477         vol_slider->setToolTip("Volume 0 %");
478     song_total_time = 0;
479     song_previous_time = 0;
480     b_skip_khz = false;
481     b_repeat = false;
482     b_random = false;
483     b_single = false;
484     b_consume = false;
485     b_xfade = false;
486     b_mpd_connected = false;
487     b_mpd_sets_volume = false;
488     b_stream = false;
489     b_minmax_busy = false;
490     b_settings_hidden = false;
491     b_browser_hidden = false;
492     b_nosong = false;
493     b_lock_progress = false;
494     b_really_close = false;
495     b_need_newSong = false;
496     b_reshow_browser = false;
497     b_reshow_settings = false;
498     current_art_path = "nopic";
499 
500     if (config->scroller_delay < 20)
501         config->scroller_delay = 20;
502     title_scroller->set_delay( config->scroller_delay );
503 
504     // 'load' or they will disappear after a repaint
505     img_mn_play = QIcon(":/mn_play");
506     img_mn_pause = QIcon(":/mn_pause");
507     pxb_led_playing.load(":/led_playing");
508     pxb_led_noconn.load(":/led_noconn");
509     pxb_led_paused.load(":/led_paused");
510     pxb_led_stopped.load(":/led_stopped");
511     pxb_led_idle.load(":/led_idle");
512 
513     if (config->use_trayicon)
514     {
515         the_trayicon = new qm_trayIcon(this);
516 
517         the_trayicon->show();
518 
519         //the_trayicon->installEventFilter(new qm_eventHandler(this)); // No events are filtered ever
520 
521         QObject::connect(the_trayicon, SIGNAL(clicked()), this, SLOT(on_tray_clicked()));
522         QObject::connect(the_trayicon, SIGNAL(signal_tray_menu(int)), this, SLOT(on_signal(int)));
523 
524         the_trayicon->set_mode(ID_idle);
525 
526         b_use_trayicon = true;
527     }
528     else
529         b_use_trayicon = false;
530 
531     set_colors();
532     set_fonts();
533 
534     move(config->player_X, config->player_Y);
535 
536     vol_slider->setFocus(Qt::OtherFocusReason);
537 }
538 
539 
lock_progress()540 void qm_player::lock_progress()
541 {
542     // fade the album art last
543     if (b_minmax_xfade)
544     {
545         alphacycler += 6;
546         if (alphacycler >= 255)
547         {
548             b_minmax_busy = false;
549             lb_albumart->setPixmap(pxb_albmart);
550             maximizer->stop();
551             return ; // done
552         }
553 
554         int a = alphacycler;
555         QImage xfade = img_xfade_input;
556         for ( int j = 0; j < albumart_H; j++ )
557         {
558             QRgb *px = (reinterpret_cast<QRgb *>(xfade.scanLine(j)) );
559             for ( int k = 0; k < albumart_W; k++ )
560             {
561                 uchar r = uchar( ( int(qRed(*px))   * a  +  cR * (255 - a)) / 255 );
562                 uchar g = uchar( ( int(qGreen(*px)) * a  +  cG * (255 - a)) / 255 );
563                 uchar b = uchar( ( int(qBlue(*px))  * a  +  cB * (255 - a)) / 255 );
564                 *px = qRgba( r, g, b, 255);
565                 px++;
566             }
567         }
568 
569         pxb_xfading = QPixmap::fromImage(xfade);
570         lb_albumart->setPixmap(pxb_xfading);
571         return;
572     }
573 
574     window_H += 16;
575     if (window_H <= window_H_max)
576     {
577         setFixedSize(window_W_max, window_H);
578     }
579     else
580     {
581         window_H = window_H_max;
582         setFixedSize(window_W_max, window_H_max);
583         center_widget->show();
584         b_minmax_xfade = true;
585     }
586 }
587 
588 
on_tray_clicked()589 void qm_player::on_tray_clicked()
590 {
591     if (isVisible())
592     {
593         hide();
594     }
595     else
596     {
597         showNormal();
598     }
599 }
600 
601 
on_curentsong_deleted()602 void qm_player::on_curentsong_deleted()
603 {
604     current_songinfo->nosong = true;
605     on_new_song();
606     set_status(MPD_STATE_UNKNOWN); // also sets the plist_view
607 }
608 
609 
on_new_song()610 void qm_player::on_new_song()
611 {
612     kbps_count_down = 0;
613     b_skip_khz = false;
614 
615     if (current_songinfo->nosong)
616     {
617         if (b_nosong)
618             return;
619         // else
620         b_nosong = true;
621         current_type = TP_NOSONG;
622         current_songnr = -1;
623         browser_window->plist_view->set_newsong(-1);
624         return;
625     }
626     else
627     {
628         browser_window->plist_view->set_newsong(current_songinfo->songNr);
629         current_type = current_songinfo->type;
630     }
631 
632     // in "idle" state we didn't set the title etc.
633     if (current_status == MPD_STATE_UNKNOWN)
634     {
635         b_need_newSong = true;
636         return;
637     }
638     else
639         b_need_newSong = false;
640 
641     if (current_songnr != current_songinfo->songNr)
642     {
643         current_songnr = current_songinfo->songNr;
644         printf ("New song : %i\n", current_songnr);
645     }
646     b_nosong = false;
647 
648     QString fname = "";
649     QString path = "";
650 
651     if (!current_songinfo->file.isEmpty())
652     {
653         fname = current_songinfo->file;
654         // current dir, from MPD's music dir, exc the last "/"
655         current_mpd_dir = fname.left(fname.lastIndexOf("/"));
656         // path, from MPD's music dir, inc the last "/"
657         path = fname.left(fname.lastIndexOf("/") + 1);
658         // remove path, keep filename only
659         int i = fname.lastIndexOf( '/' ) + 1;
660         fname = fname.right(fname.length() - i);
661     }
662 
663     if (current_songinfo->type == TP_SONG)
664         a_loadtags->setEnabled(true);
665     else
666         a_loadtags->setEnabled(false);
667 
668     // streams : path.startsWith("http:")
669     if (current_songinfo->type == TP_STREAM)
670     {
671         current_mpd_dir = "";
672         set_albumart(path, TP_STREAM);
673         ds_progress->setValue(0);
674         lb_extension->setText("URL");
675         lb_album->setText(tr(""));
676         lb_comment->setText(tr("Audio stream"));
677         // note: newSong->artist is NULL !
678 
679         if (!current_songinfo->title.isEmpty())
680         {
681             title_scroller->set_title(current_songinfo->title);
682             if (b_use_trayicon)
683                 the_trayicon->set_tip(current_songinfo->title);
684         }
685         else
686         {
687             if (!current_songinfo->name.isEmpty())
688             {
689                 title_scroller->set_title(current_songinfo->name);
690                 if (b_use_trayicon)
691                     the_trayicon->set_tip(current_songinfo->name);
692             }
693             else
694             {
695                 title_scroller->set_title(tr("no info"));
696                 if (b_use_trayicon)
697                     the_trayicon->set_tip(tr("no info"));
698             }
699         }
700 
701         b_stream = true;
702         return;
703     }
704     else
705         b_stream = false;
706 
707     // albumart
708     if ( (config->mpd_musicpath_status == 1 || current_songinfo->type == TP_SONGX ) && !config->disable_albumart)
709         set_albumart(path, current_songinfo->type);
710     else
711         set_albumart("nopic", TP_NOSONG);
712 
713     // extension
714     if (fname.isEmpty())
715     {
716         lb_extension->setText("");
717     }
718     else
719     {
720         QString aString = fname;
721         int i = aString.lastIndexOf( '.' ) + 1;
722         aString = aString.right(aString.length() - i);
723         aString = aString.toUpper();
724         lb_extension->setText(aString);
725     }
726 
727     if (current_songinfo->time)
728     {
729         song_total_time = current_songinfo->time;
730         ds_progress->setRange(0,song_total_time);
731     }
732 
733     // artist
734     QString artist = "?";
735     if (!current_songinfo->artist.isEmpty())
736         artist = current_songinfo->artist;
737 
738     // title
739     QString title = "?";
740     if (!current_songinfo->title.isEmpty())
741         title = current_songinfo->title;
742 
743 
744     if (current_songinfo->artist.isEmpty() && current_songinfo->title.isEmpty())
745     {
746         if (fname.isEmpty())
747         {
748             title_scroller->set_title("[?]");
749             if (b_use_trayicon)
750                 the_trayicon->set_tip(" " + tr("No Info") + " ");
751         }
752         else
753         {
754             title_scroller->set_title(fname);
755             if (b_use_trayicon)
756                 the_trayicon->set_tip(" " + fname + " ");
757         }
758     }
759     else
760     {
761         title_scroller->set_title(artist, title);
762         if (b_use_trayicon)
763         {
764             QString artist_tip = "&nbsp;<b>" + artist + "</b>&nbsp;";
765             QString title_tip = "&nbsp;<i>" + title + "&nbsp;</i>";
766             the_trayicon->set_tip( artist_tip + "<br>" + title_tip);
767         }
768     }
769 
770     //album
771     QString album = "<b>?</b>";
772     if (!current_songinfo->album.isEmpty())
773         album = "<b>" + current_songinfo->album + "</b>";
774     // year
775     if (!current_songinfo->date.isEmpty())
776         album.append("<br>" + current_songinfo->date);
777 
778     lb_album->setText(album);
779     // comment
780     lb_comment->setFixedSize(122, 200 - (lb_album->height() + 4) ); // 4 = 2 x lb_album margin
781     lb_comment->setText(current_songinfo->comment);
782 }
783 
784 
on_new_status(mpd_status * sInfo)785 void qm_player::on_new_status(mpd_status *sInfo)
786 {
787     if (sInfo == nullptr)
788         return;
789 
790     // set the playback modes in the playlist menu
791     if ( mpd_status_get_repeat(sInfo) != b_repeat)
792     {
793         browser_window->set_menu_repeat(mpd_status_get_repeat(sInfo));
794         b_repeat = mpd_status_get_repeat(sInfo);
795     }
796 
797     if (mpd_status_get_random(sInfo) != b_random)
798     {
799         browser_window->set_menu_random(mpd_status_get_random(sInfo));
800         b_random = mpd_status_get_random(sInfo);
801     }
802 
803     if (mpd_status_get_single(sInfo) != b_single)
804     {
805         browser_window->set_menu_single(mpd_status_get_single(sInfo));
806         b_single = mpd_status_get_single(sInfo);
807     }
808 
809     if (mpd_status_get_consume(sInfo) != b_consume)
810     {
811         browser_window->set_menu_consume(mpd_status_get_consume(sInfo));
812         b_consume = mpd_status_get_consume(sInfo);
813     }
814 
815     if (mpd_status_get_crossfade(sInfo) > 0 && !b_xfade)
816     {
817         b_xfade = true;
818         browser_window->set_menu_xfade(b_xfade);
819     }
820 
821     if (mpd_status_get_crossfade(sInfo) == 0 && b_xfade)
822     {
823         b_xfade = false;
824         browser_window->set_menu_xfade(b_xfade);
825     }
826 
827     // if status has changed...
828     if (b_nosong && current_status != MPD_STATE_UNKNOWN)
829         set_status(MPD_STATE_UNKNOWN);
830     else
831         if (mpd_status_get_state(sInfo) != current_status)
832             set_status(mpd_status_get_state(sInfo));
833 
834     // set the other status info
835     if (mpd_status_get_state(sInfo) != MPD_STATE_UNKNOWN && current_status != MPD_STATE_UNKNOWN)
836     {
837         int timenow = static_cast<int>(mpd_status_get_elapsed_time(sInfo));
838 
839         if (!b_stream && !b_lock_progress && song_total_time > 0)
840         {
841             if (timenow != song_previous_time)
842             {
843                 song_previous_time = timenow;
844                 // some tracks play a bit too long (honestly)
845                 if (timenow > song_total_time)
846                     timenow = song_total_time;
847                 ds_progress->setValue(timenow);
848             }
849         }
850 
851         if (b_stream || song_total_time == 0)
852         {
853             lb_time->setText("[&#187;]");
854         }
855         else
856         {
857             if (config->use_timeleft)
858                 timenow = song_total_time - timenow;
859 
860             QString nowtime = "";
861             if (config->use_timeleft)
862                 nowtime += "-";
863             nowtime += into_time(static_cast<int>(timenow));
864             lb_time->setText(nowtime + " [" + into_time(static_cast<int>(song_total_time)) + "]");
865         }
866 
867         if (kbps_count_down == 0)
868         {
869             kbps_count_down = 4;
870 
871             uint kbps = mpd_status_get_kbit_rate(sInfo);
872             if (kbps) // 0 means unknown. Never NULL
873                 lb_kbps->setText(QString::number(kbps) + " kb/s ");
874             else
875                 lb_kbps->setText("");
876 
877             if (!b_skip_khz)
878             {
879                 b_skip_khz = true;
880                 if (mpd_status_get_audio_format(sInfo) != nullptr) // 0 means unknown. Can return NULL, esp. with streams!
881                 {
882                     double dbl_khz = static_cast<double>(mpd_status_get_audio_format(sInfo)->sample_rate) / 1000;
883                     lb_kHz->setText(QString::number(dbl_khz) + " kHz");
884                     b_skip_khz = true;
885                 }
886                 else
887                     lb_kHz->setText("");
888             }
889             else
890                 b_skip_khz = false;
891         }
892         else
893             kbps_count_down--;
894     }
895 
896     if (current_volume != mpd_status_get_volume(sInfo))
897     {
898         b_mpd_sets_volume = true;
899         /* slider Scale is set 0 to 100
900             MPD also reports 0 to 100 */
901         current_volume = mpd_status_get_volume(sInfo);
902         vol_slider->setValue(current_volume);
903         if (config->show_tooltips)
904             vol_slider->setToolTip(tr("Volume") + " " + QString::number(current_volume) + " %");
905         b_mpd_sets_volume = false;
906     }
907 }
908 
909 
retranslateUI()910 void qm_player::retranslateUI()
911 {
912     if (config->show_tooltips)
913     {
914         lb_time->setToolTip(tr("Click to toggle time mode"));
915         bt_sizer->setToolTip(tr("Mini-Maxi mode"));
916         bt_browser->setToolTip(tr("Media Browser & Playlist"));
917         bt_setts->setToolTip(tr("Settings"));
918     }
919 }
920 
921 // Signal handler.
on_signal(int sigID)922 void qm_player::on_signal(int sigID)
923 {
924     switch (sigID)
925     {
926         case ID_prev:
927         {
928             if (current_status != MPD_STATE_PLAY || !b_mpd_connected)
929                 break;
930             mpdCom->prev();
931             break;
932         }
933 
934         case ID_stop:
935         {
936             kbps_count_down = 0;
937             b_skip_khz = false;
938 
939             if (current_status == MPD_STATE_UNKNOWN ||
940                     current_status == MPD_STATE_STOP || !b_mpd_connected)
941                 break;
942 
943             set_status(MPD_STATE_STOP, "");
944             title_scroller->pause(true);
945             mpdCom->stop();
946             break;
947         }
948 
949         case ID_play:
950         {
951             kbps_count_down = 0;
952             b_skip_khz = false;
953 
954             if (!b_mpd_connected)
955                 break;
956 
957             switch (current_status)
958             {
959                 case MPD_STATE_PLAY:
960                 {
961                     set_status(MPD_STATE_PAUSE, "");
962                     mpdCom->pause();
963                     break;
964                 }
965 
966                 case MPD_STATE_PAUSE:
967                 {
968                     set_status(MPD_STATE_PLAY, "");
969                     mpdCom->resume();
970                     break;
971                 }
972 
973                 case MPD_STATE_STOP:
974                 {
975                     set_status(MPD_STATE_PLAY, "");
976                     mpdCom->play();
977                     break;
978                 }
979 
980                 case MPD_STATE_UNKNOWN:
981                 {
982                     set_status(MPD_STATE_PLAY, "");
983                     mpdCom->play();
984                     break;
985                 }
986 
987                 default:
988                     break;
989             }
990             break;
991         }
992 
993         case ID_next:
994         {
995             if (current_status != MPD_STATE_PLAY || !b_mpd_connected)
996                 break;
997             mpdCom->next();
998             break;
999         }
1000 
1001         case ID_sets:
1002         {
1003             if (settings_window->isVisible())
1004                 settings_window->hide();
1005             else
1006             {
1007                 settings_window->set_config(config); // reset unsaved changes
1008                 settings_window->show();
1009                 settings_window->setWindowState(Qt::WindowNoState);
1010             }
1011             break;
1012         }
1013 
1014         case ID_plst:
1015         {
1016             if (browser_window->isVisible())
1017                 browser_window->hide();
1018             else
1019             {
1020                 browser_window->show();
1021                 browser_window->setWindowState(Qt::WindowNoState);
1022             }
1023             break;
1024         }
1025 
1026         case ID_mmax:
1027         {
1028             if (b_minmax_busy)
1029                 break;
1030 
1031             if (config->player_maxmode)
1032             {
1033                 img_xfade_input = pxb_albmart.toImage();
1034                 b_minmax_xfade = true;
1035                 b_minmax_busy = true;
1036                 alphacycler = 255;
1037                 minimizer->start(12);
1038                 config->player_maxmode = false;
1039             }
1040             else
1041             {
1042                 img_xfade_input = pxb_albmart.toImage();
1043                 b_minmax_xfade = false;
1044                 b_minmax_busy = true;
1045                 alphacycler = 0;
1046                 maximizer->start(12);
1047                 config->player_maxmode = true;
1048             }
1049             break;
1050         }
1051 
1052         case ID_time:
1053         {
1054             config->use_timeleft = !config->use_timeleft;
1055             break;
1056         }
1057 
1058         case ID_exit:
1059         {
1060             b_really_close = true;
1061             close();
1062             break;
1063         }
1064 
1065         default:
1066             break;
1067     }
1068     // focus goes back to the volume slider
1069     vol_slider->setFocus(Qt::OtherFocusReason);
1070 }
1071 
1072 
set_status(int status,QString message)1073 void qm_player::set_status(int status, QString message)
1074 {
1075     if (!message.isEmpty())
1076         title_scroller->set_title(message);
1077 
1078     if (status == current_status)
1079         return;
1080 
1081     // in "idle" mode only respond to play and not connected
1082     if (current_status == MPD_STATE_UNKNOWN && status != MPD_STATE_PLAY && status != -1)
1083         return;
1084 
1085     if (b_need_newSong)
1086         mpdCom->reset_current_song();
1087 
1088     browser_window->plist_view->set_status(status);
1089 
1090     switch (status)
1091     {
1092         case -1: // not connected
1093         {
1094             bt_playpause->setIcon(img_mn_play);
1095             lb_time->setText("");
1096             lb_kHz->setText("");
1097             lb_extension->setText("");
1098             lb_kbps->setText("");
1099             lb_album->setText("");
1100             lb_comment->setText("");
1101             set_albumart("nopic", TP_NOSONG);
1102             ds_progress->setStyleSheet(
1103                 "QSlider::groove:horizontal {"
1104                 "margin: 0 0 0 0;"
1105                 "border: 1px solid #aaa;"
1106                 "background-image: url(:/groove_bg_noconn.png);"
1107                 "height: 3px;"
1108                 "border-radius: 2px; }");
1109             ds_progress->setValue(0);
1110             if (b_use_trayicon)
1111             {
1112                 the_trayicon->set_mode(ID_nocn);
1113             }
1114             break;
1115         }
1116 
1117         case MPD_STATE_STOP: // 1
1118         {
1119             bt_playpause->setIcon(img_mn_play);
1120             title_scroller->pause(true);
1121             ds_progress->setStyleSheet(
1122                 "QSlider::groove:horizontal {"
1123                 "margin: 0 0 0 0;"
1124                 "border: 1px solid #aaa;"
1125                 "background-image: url(:/groove_bg_conn.png);"
1126                 "height: 3px;"
1127                 "border-radius: 2px; }");
1128             ds_progress->setValue(0);
1129             if (b_use_trayicon)
1130                 the_trayicon->set_mode(ID_stop);
1131             break;
1132         }
1133 
1134         case MPD_STATE_PLAY: // 2
1135         {
1136             bt_playpause->setIcon(img_mn_pause);
1137             title_scroller->pause(false);
1138             ds_progress->setStyleSheet(
1139                 "QSlider::groove:horizontal {"
1140                 "margin: 0 0 0 0;"
1141                 "border: 1px solid #aaa;"
1142                 "background-image: url(:/groove_bg_conn.png);"
1143                 "height: 3px;"
1144                 "border-radius: 2px;}"
1145                 "QSlider::sub-page:horizontal {"
1146                 "border-image: url(:/groove_sub_play.png); }");
1147             if (b_use_trayicon)
1148                 the_trayicon->set_mode(ID_play);
1149             break;
1150         }
1151 
1152         case MPD_STATE_PAUSE: // 3
1153         {
1154             bt_playpause->setIcon(img_mn_play);
1155             title_scroller->pause(true);
1156             ds_progress->setStyleSheet(
1157                 "QSlider::groove:horizontal {"
1158                 "margin: 0 0 0 0;"
1159                 "border: 1px solid #aaa;"
1160                 "background-image: url(:/groove_bg_conn.png);"
1161                 "height: 3px;"
1162                 "border-radius: 2px;}"
1163                 "QSlider::sub-page:horizontal {"
1164                 "border-image: url(:/groove_sub_play.png); }");
1165             if (b_use_trayicon)
1166                 the_trayicon->set_mode(ID_paus);
1167             break;
1168         }
1169 
1170         default: // 0 (MPD_STATE_UNKNOWN) "Idle"
1171         {
1172             title_scroller->set_title(" ");
1173             bt_playpause->setIcon(img_mn_play);
1174             lb_time->setText("");
1175             lb_kHz->setText("");
1176             lb_extension->setText("");
1177             lb_kbps->setText("");
1178             lb_album->setText("");
1179             lb_comment->setText("");
1180             set_albumart("nopic", TP_NOSONG);
1181             ds_progress->setStyleSheet(
1182                 "QSlider::groove:horizontal {"
1183                 "margin: 0 0 0 0;"
1184                 "border: 1px solid #aaa;"
1185                 "background-image: url(:/groove_bg_conn.png);"
1186                 "height: 3px;"
1187                 "border-radius: 2px; }");
1188             ds_progress->setValue(0);
1189             if (b_use_trayicon)
1190             {
1191                 the_trayicon->set_mode(ID_idle);
1192             }
1193             break;
1194         }
1195     }
1196     current_status = status;
1197 }
1198 
1199 
into_time(int time)1200 QString qm_player::into_time(int time)
1201 {
1202     QString formattedTime = "";
1203     int mins = time / 60;
1204     formattedTime += QString::number((mins)) + ":";
1205     int secs = time % 60;
1206     if (secs < 10)
1207         formattedTime += "0";
1208     formattedTime += QString::number((secs));
1209     return formattedTime;
1210 }
1211 
1212 
set_colors()1213 void qm_player::set_colors()
1214 {
1215     QPalette pal_main(this->palette());
1216     QPalette pal_album (this->palette());
1217     QPalette pal_default(this->palette());
1218 
1219     if (config->rb_qmcool_checked)
1220     {
1221         // display
1222         QColor fg_color = QColor("#e4f3fc");
1223         QColor bg_color = QColor("#505f72");
1224         pal_main.setColor(QPalette::Window, QColor(bg_color));
1225         pal_main.setColor(QPalette::Foreground, QColor(fg_color));
1226         // siblings are transparent by default
1227         main_display->setPalette(pal_main);
1228         main_display->setAutoFillBackground(true);
1229         lb_kbps->setPalette(pal_main);
1230         lb_kbps->setAutoFillBackground(true);
1231         lb_time->setPalette(pal_main);
1232         lb_time->setAutoFillBackground(true);
1233         title_scroller->setPalette(pal_main);
1234         title_scroller->setAutoFillBackground(true);
1235         lb_kHz->setPalette(pal_main);
1236         lb_kHz->setAutoFillBackground(true);
1237         lb_extension->setPalette(pal_main);
1238         lb_extension->setAutoFillBackground(true);
1239         // browser titles
1240         if (config->color_browser)
1241             browser_window->set_colors(pal_main);
1242         else
1243             browser_window->set_colors(pal_default);
1244         // album info
1245         if (config->color_albuminfo)
1246         {
1247             fg_color.setHsv(fg_color.hue(), fg_color.saturation(), 64);
1248             bg_color.setHsv(bg_color.hue(), bg_color.saturation()/3, 200);
1249             pal_album.setColor(QPalette::Window, bg_color);
1250             pal_album.setColor(QPalette::Foreground, fg_color);
1251             center_widget->setAutoFillBackground(true);
1252             center_widget->setPalette(pal_album);
1253             // to fill transparency in (album art) images:
1254             cR = bg_color.red();
1255             cG = bg_color.green();
1256             cB = bg_color.blue();
1257         }
1258     }
1259     else
1260     if (config->rb_custom_checked)
1261     {
1262         // display
1263         QColor fg_color = QColor(config->color_fg);
1264         QColor bg_color = QColor(config->color_bg);
1265         pal_main.setColor(QPalette::Window, QColor(bg_color));
1266         pal_main.setColor(QPalette::Foreground, QColor(fg_color));
1267         // siblings are transparent by default
1268         main_display->setPalette(pal_main);
1269         main_display->setAutoFillBackground(true);
1270         lb_kbps->setPalette(pal_main);
1271         lb_kbps->setAutoFillBackground(true);
1272         lb_time->setPalette(pal_main);
1273         lb_time->setAutoFillBackground(true);
1274         title_scroller->setPalette(pal_main);
1275         title_scroller->setAutoFillBackground(true);
1276         lb_kHz->setPalette(pal_main);
1277         lb_kHz->setAutoFillBackground(true);
1278         lb_extension->setPalette(pal_main);
1279         lb_extension->setAutoFillBackground(true);
1280         // browser titles
1281         if (config->color_browser)
1282             browser_window->set_colors(pal_main);
1283         else
1284             browser_window->set_colors(pal_default);
1285         // album info
1286         if (config->color_albuminfo)
1287         {
1288             fg_color.setHsv(fg_color.hue(), fg_color.saturation(), 64);
1289             bg_color.setHsv(bg_color.hue(), bg_color.saturation()/3, 200);
1290             pal_album.setColor(QPalette::Window, bg_color);
1291             pal_album.setColor(QPalette::Foreground, fg_color);
1292             center_widget->setAutoFillBackground(true);
1293             center_widget->setPalette(pal_album);
1294             // to fill transparency in (album art) images:
1295             cR = bg_color.red();
1296             cG = bg_color.green();
1297             cB = bg_color.blue();
1298         }
1299     }
1300     else // config->rb_sysdef_checked
1301     {
1302         // display
1303         main_display->setPalette(pal_default);
1304         main_display->setAutoFillBackground(false);
1305         lb_kbps->setPalette(pal_default);
1306         lb_kbps->setAutoFillBackground(false);
1307         lb_time->setPalette(pal_default);
1308         lb_time->setAutoFillBackground(false);
1309         title_scroller->setPalette(pal_default);
1310         title_scroller->setAutoFillBackground(false);
1311         lb_kHz->setPalette(pal_default);
1312         lb_kHz->setAutoFillBackground(false);
1313         lb_extension->setPalette(pal_default);
1314         lb_extension->setAutoFillBackground(false);
1315         center_widget->setAutoFillBackground(false);
1316         // browser titles
1317         browser_window->set_colors(pal_default);
1318         // album info
1319         if (config->color_albuminfo)
1320         {
1321             center_widget->setAutoFillBackground(false);
1322             center_widget->setPalette(pal_default);
1323             // to fill transparency in (album art) images:
1324             QColor bg_color = pal_default.color(QPalette::Window);
1325             cR = bg_color.red();
1326             cG = bg_color.green();
1327             cB = bg_color.blue();
1328         }
1329     }
1330 
1331     if (!config->color_albuminfo)
1332     {
1333         QColor bg_color = pal_default.color(QPalette::Window);
1334         cR = bg_color.red();
1335         cG = bg_color.green();
1336         cB = bg_color.blue();
1337         center_widget->setAutoFillBackground(false);
1338         center_widget->setPalette(pal_default);
1339     }
1340 
1341     set_albumart(current_art_path, current_type);
1342 }
1343 
1344 //  Mouse pressed on progress slider
lock_progress(QMouseEvent * e)1345 void qm_player::lock_progress(QMouseEvent *e)
1346 {
1347     if (!b_stream && current_status == MPD_STATE_PLAY && b_mpd_connected)
1348     {
1349         b_lock_progress = true;
1350         // Get mouse x pos within widget
1351         int x = e->x();
1352         x = (x * song_total_time) / 324; // 324 is width of widget
1353         ds_progress->setValue(x);
1354     }
1355 }
1356 
1357 // Mouse released on progress slider.
unlock_progress()1358 void qm_player::unlock_progress()
1359 {
1360     if (!b_stream && current_status == MPD_STATE_PLAY && b_mpd_connected)
1361     {
1362         mpdCom->set_seek( static_cast<uint>(ds_progress->value()) );
1363         b_lock_progress = false;
1364     }
1365 }
1366 
1367 
set_fonts()1368 void qm_player::set_fonts()
1369 {
1370     QFont font;
1371 
1372     font.setPointSize(config->maintitle_fontsize);
1373     title_scroller->setFont(font);
1374 
1375     font.setPointSize(config->codecinfo_fontsize);
1376     lb_extension->setFont (font);
1377     lb_kHz->setFont (font);
1378     lb_kbps->setFont (font);
1379 
1380     QLabel testlabel;
1381     testlabel.setFont (font);
1382     testlabel.setText("1024 kb/s");
1383     int w_kbps = (testlabel.minimumSizeHint()).width ();
1384 
1385     bool ok_to_show_khz = true;
1386     // hide kHz label when kb/s needs the space
1387     if (w_kbps > 64)
1388     {
1389         lb_kHz->hide();
1390         ok_to_show_khz = false;
1391         lb_kbps->setGeometry(66, 28, w_kbps, 20);
1392     }
1393     else
1394     {
1395         lb_kHz->show();
1396         lb_kbps->setGeometry(66, 28, 64, 20);
1397     }
1398 
1399     font.setPointSize(config->time_fontsize);
1400     lb_time->setFont (font);
1401 
1402     testlabel.setFont (font);
1403     testlabel.setText("-00:00 [00:00]");
1404     int w_time = (testlabel.minimumSizeHint()).width ();
1405 
1406     // hide kHz label when time needs the space
1407     if (w_time > 114)
1408     {
1409         lb_kHz->hide();
1410         lb_time->setGeometry(QRect(200 - (w_time - 114), 28, w_time, 20));
1411     }
1412     else
1413     {
1414         if (ok_to_show_khz)
1415             lb_kHz->show();
1416         lb_time->setGeometry(QRect(200, 28, 114, 20));
1417     }
1418 
1419     font.setPointSize(config->album_fontsize);
1420     lb_album->setFont (font);
1421 
1422     font.setPointSize(config->comment_fontsize);
1423     lb_comment->setFont (font);
1424 
1425     font.setPointSize(config->liblist_fontsize);
1426     browser_window->plist_view->setFont(font);
1427     browser_window->lib_view->setFont(font);
1428 }
1429 
1430 
set_albumart(QString sub_path,int type)1431 void qm_player::set_albumart(QString sub_path, int type)
1432 {
1433     QImage temp;
1434     bool b_file_from_disk_or_tag = true;
1435     bool b_file_ok = false;
1436 
1437     if (type == TP_NOSONG || sub_path == "nopic" || sub_path.isEmpty())
1438     {
1439         img_nopic.load(":/nopic");
1440         {  // fill transparency with background color (for fading)
1441             for ( int j = 0; j < 200; j++ )
1442             {
1443                 QRgb *px = (reinterpret_cast<QRgb *>(img_nopic.scanLine(j)) );
1444                 for ( int k = 0; k < 200; k++ )
1445                 {
1446                     int a = qAlpha(*px);
1447                     uchar r = uchar( ( int(qRed(*px))   * a  +  cR * (255 - a)) / 255 );
1448                     uchar g = uchar( ( int(qGreen(*px)) * a  +  cG * (255 - a)) / 255 );
1449                     uchar b = uchar( ( int(qBlue(*px))  * a  +  cB * (255 - a)) / 255 );
1450                     *px = qRgba( r, g, b, 255);
1451                     px++;
1452                 }
1453             }
1454         }
1455         temp = QImage(img_nopic);
1456         current_art_path = "nopic";
1457         b_file_from_disk_or_tag = false;
1458         b_file_ok = true;
1459     }
1460 
1461     if (type == TP_STREAM || sub_path == "onair")
1462     {
1463         img_stream.load(":/onair");
1464         {  // fill transparency with background color (for fading)
1465             for ( int j = 0; j < 200; j++ )
1466             {
1467                 QRgb *px = (reinterpret_cast<QRgb *>(img_stream.scanLine(j)) );
1468                 for ( int k = 0; k < 200; k++ )
1469                 {
1470                     int a = qAlpha(*px);
1471                     uchar r = uchar( ( int(qRed(*px))   * a  +  cR * (255 - a)) / 255 );
1472                     uchar g = uchar( ( int(qGreen(*px)) * a  +  cG * (255 - a)) / 255 );
1473                     uchar b = uchar( ( int(qBlue(*px))  * a  +  cB * (255 - a)) / 255 );
1474                     *px = qRgba( r, g, b, 255);
1475                     px++;
1476                 }
1477             }
1478         }
1479         temp = QImage(img_stream);
1480         current_art_path = "onair";
1481         b_file_from_disk_or_tag = false;
1482         b_file_ok = true;
1483     }
1484 
1485     // ALBUM-ART:
1486 
1487     QString artPath;
1488     if (type == TP_SONGX)
1489     {
1490         if ( sub_path.startsWith("/") )
1491             artPath = sub_path;
1492         else
1493             artPath = "/" +  sub_path;
1494     }
1495     else // type == TP_SONG
1496         artPath = config->mpd_musicpath + sub_path;
1497 
1498     // first try tag
1499     bool b_image_from_tag = false;
1500     if (b_file_from_disk_or_tag)
1501     {
1502         QString filepath = current_songinfo->file;
1503         int i = filepath.lastIndexOf( '/' );
1504         filepath = filepath.right(filepath.length() - i);
1505         filepath = artPath + filepath;
1506 
1507         // try to load the image
1508         temp = getTagImage(filepath);
1509         if (temp.isNull())
1510         {
1511             b_file_ok =  false;
1512         }
1513         else
1514         {
1515             b_file_ok =  true;
1516             b_image_from_tag = true;
1517             current_art_path = sub_path;
1518         }
1519     }
1520 
1521 
1522     // next try image file if tag failed
1523     if (b_file_from_disk_or_tag && !b_file_ok)
1524     {
1525         QDir dir(artPath);
1526         if (!dir.exists())
1527             printf ("Album art directory : not found\n");
1528         else
1529         if(!dir.isReadable())
1530             printf ("Album art directory : not readable\n");
1531         else
1532         {
1533             b_file_ok = go_find_art(artPath, "*albumart*");
1534             if (!b_file_ok)
1535                 b_file_ok = go_find_art(artPath, "*folder*");
1536             if (!b_file_ok)
1537                 b_file_ok = go_find_art(artPath, "*front*");
1538             if (!b_file_ok)
1539                 b_file_ok = go_find_art(artPath, "*cover*");
1540             if (!b_file_ok)
1541                 b_file_ok = go_find_art(artPath, "*");  // anything else?
1542 
1543             if (!b_file_ok)
1544                 artPath = "nopic";
1545 
1546             current_art_path = sub_path;
1547 
1548             // load the image
1549             if (b_file_ok)
1550             {
1551                 temp.load(artPath);
1552 
1553                 if (temp.isNull())
1554                 {
1555                     b_file_ok = false;
1556                     printf ("Album art : error loading file\n");
1557                 }
1558             }
1559         }
1560     }
1561 
1562     if (!b_file_ok)
1563     {
1564         current_art_path = "nopic";
1565         temp = QImage(img_nopic);
1566         b_file_from_disk_or_tag = false;
1567     }
1568 
1569     // resize the image
1570     if (b_file_from_disk_or_tag)
1571         temp = temp.scaled( 200, 200, Qt::KeepAspectRatio , Qt::SmoothTransformation );
1572     albumart_H = temp.height();
1573     albumart_W = temp.width();
1574 
1575     if (b_file_from_disk_or_tag)
1576     {
1577         //  add alpha for xfading
1578         if (!temp.hasAlphaChannel())
1579         {
1580             QImage aChannel = QImage(albumart_W, albumart_H, QImage::Format_RGB32);
1581             aChannel.fill(0xFFFFFFFF);
1582             temp.setAlphaChannel(aChannel);
1583         }
1584         else
1585         {  //  fill transparency with background color (for fading)
1586             for ( int j = 0; j <albumart_H; j++ )
1587             {
1588                 QRgb *px = (reinterpret_cast<QRgb *>(temp.scanLine(j)) );
1589                 for ( int k = 0; k < albumart_W; k++ )
1590                 {
1591                     int a = qAlpha(*px);
1592                     uchar r = uchar( ( int(qRed(*px))   * a  +  cR * (255 - a)) / 255 );
1593                     uchar g = uchar( ( int(qGreen(*px)) * a  +  cG * (255 - a)) / 255 );
1594                     uchar b = uchar( ( int(qBlue(*px))  * a  +  cB * (255 - a)) / 255 );
1595                     *px = qRgba( r, g, b, 255);
1596                     px++;
1597                 }
1598             }
1599         }
1600     }
1601 
1602     // add border
1603     if (b_file_from_disk_or_tag)
1604     {
1605         for (int  h = 0; h < albumart_H; h++)
1606         {
1607             for (int  w = 0; w < albumart_W; w++)
1608             {
1609                 if (h == 0 || h == albumart_H-1 || w == 0 || w == albumart_W-1)
1610                 {
1611                     temp.setPixel(w, h, 0xFF768B96);
1612                 }
1613             }
1614         }
1615     }
1616 
1617     // finally show the image
1618     if (config->player_maxmode)
1619     {
1620         pxb_albmart  = QPixmap::fromImage(temp);
1621         pxb_xfading = QPixmap::fromImage(temp);
1622         lb_albumart->setPixmap(pxb_albmart);
1623     }
1624     else
1625     {
1626         pxb_albmart  = QPixmap::fromImage(temp);
1627         // set alpha to 0
1628         for (int  h = 0; h < albumart_H; h++)
1629         {
1630             for (int  w = 0; w < albumart_W; w++)
1631             {
1632                 QRgb RGB = temp.pixel(w,h);
1633                 temp.setPixel(w, h, qRgba( qRed(RGB), qGreen(RGB), qBlue(RGB), 0));
1634             }
1635         }
1636         pxb_xfading = QPixmap::fromImage(temp);
1637         lb_albumart->setPixmap(pxb_xfading);
1638     }
1639 
1640     // and set tooltip
1641     if (config->show_tooltips && b_file_ok)
1642     {
1643         if (b_image_from_tag)
1644             lb_albumart->setToolTip(tr("Album art (from tag)"));
1645         else
1646             lb_albumart->setToolTip(tr("Album art (from file)"));
1647     }
1648     if (config->show_tooltips && !b_file_ok)
1649         lb_albumart->setToolTip(tr("No album art"));
1650 }
1651 
1652 
go_find_art(QString & artPath,QString findthis)1653 bool qm_player::go_find_art(QString &artPath, QString findthis)
1654 {
1655     QDir dir(artPath);
1656     dir.setSorting(QDir::Type);
1657     QStringList namefilter;
1658 
1659     namefilter << findthis + ".jpg" << findthis + ".png" << findthis + ".gif" << findthis + ".bmp" << findthis + ".jpeg";
1660 
1661     QStringList files = dir.entryList(namefilter, QDir::Files);
1662     if (files.isEmpty())
1663         return false;
1664 
1665     artPath.append(files.at(0));
1666     return true;
1667 }
1668 
1669 
on_contextmenu()1670 void qm_player::on_contextmenu()
1671 {
1672     // no song, stream or not connected -> no menu
1673     if (b_nosong || b_stream || !b_mpd_connected)
1674         return;
1675     context_menu->exec(QCursor::pos());
1676 }
1677 
1678 
show_albumart()1679 void qm_player::show_albumart()
1680 {
1681     QString full_path;
1682     if (current_type == TP_SONGX)
1683     {
1684         if ( current_mpd_dir.startsWith("/") )
1685             full_path = current_mpd_dir;
1686         else
1687             full_path = "/" +  current_mpd_dir;
1688     }
1689     else
1690     if (current_type == TP_SONG)
1691     {
1692         full_path = config->mpd_musicpath + current_mpd_dir;
1693     }
1694     else
1695         return;
1696 
1697     QProcess *proc = nullptr;
1698     proc->startDetached(config->art_viewer, QStringList() << full_path );
1699 }
1700 
1701 
reload_tags()1702 void qm_player::reload_tags()
1703 {
1704     if (current_type != TP_SONG)
1705         return;
1706 
1707     if (config->mpd_rescan_allowed)
1708     {
1709         qm_commandList cmdList;
1710         qm_mpd_command newCommand;
1711 
1712         newCommand.file = current_mpd_dir;
1713         newCommand.cmd = CMD_SCN;
1714         cmdList.push_back(newCommand);
1715 
1716         QString msg  = "Rescanning : " + current_mpd_dir  + "\n";
1717         printf ("%s", msg.toUtf8().constData());
1718         mpdCom->execute_cmds(cmdList, false);
1719     }
1720     else
1721         printf("Rescan not allowed\n");
1722 }
1723 
1724 
edit_tags()1725 void qm_player::edit_tags()
1726 {
1727     QString full_path;
1728     if (current_type == TP_SONGX)
1729     {
1730         if ( current_mpd_dir.startsWith("/") )
1731             full_path = current_mpd_dir;
1732         else
1733             full_path = "/" +  current_mpd_dir;
1734     }
1735     else
1736     if (current_type == TP_SONG)
1737     {
1738         full_path = config->mpd_musicpath + current_mpd_dir;
1739     }
1740     else
1741         return;
1742 
1743     QProcess *proc = nullptr;
1744     proc->startDetached(config->tag_editor, QStringList() << full_path);
1745 }
1746 
1747 
open_directory()1748 void qm_player::open_directory()
1749 {
1750     QString full_path;
1751     if (current_type == TP_SONGX)
1752     {
1753         if ( current_mpd_dir.startsWith("/") )
1754             full_path = current_mpd_dir;
1755         else
1756             full_path = "/" +  current_mpd_dir;
1757     }
1758     else
1759     if (current_type == TP_SONG)
1760     {
1761         full_path = config->mpd_musicpath + current_mpd_dir;
1762     }
1763     else
1764         return;
1765 
1766     QProcess *proc = nullptr;
1767     proc->startDetached(config->file_manager, QStringList() << full_path);
1768 }
1769 
1770 // called by the core
wakeup_call(bool show_browser)1771 void qm_player::wakeup_call(bool show_browser)
1772 {
1773 
1774     this->showNormal();
1775     if (show_browser)
1776     {
1777         browser_window->showNormal();
1778         browser_window->activateWindow();
1779     }
1780     else
1781         this->activateWindow();
1782 }
1783 
1784 
showEvent(QShowEvent * se)1785 void qm_player::showEvent(QShowEvent *se)
1786 {
1787     if (b_reshow_browser)
1788         browser_window->showNormal();
1789     if (b_reshow_settings)
1790         settings_window->showNormal();
1791     se->accept();
1792 }
1793 
1794 
hideEvent(QHideEvent * he)1795 void qm_player::hideEvent(QHideEvent *he)
1796 {
1797     if (browser_window->isVisible())
1798     {
1799         b_reshow_browser = true;
1800         browser_window->hide();
1801     }
1802     else
1803         b_reshow_browser = false;
1804 
1805     if (settings_window->isVisible())
1806     {
1807         b_reshow_settings = true;
1808         settings_window->hide();
1809     }
1810     else
1811         b_reshow_settings = false;
1812 
1813     config->player_X = x();
1814     config->player_Y = y();
1815     he->accept();
1816 }
1817 
1818 
closeEvent(QCloseEvent * ce)1819 void qm_player::closeEvent( QCloseEvent * ce )
1820 {
1821     if (!b_really_close && b_use_trayicon)
1822     {
1823         this->hide();
1824     }
1825     else
1826     {
1827         if (this->isVisible())
1828         {
1829             config->player_X = x();
1830             config->player_Y = y();
1831         }
1832         if (browser_window->isVisible())
1833         {
1834             config->browser_X = browser_window->x();
1835             config->browser_Y = browser_window->y();
1836             config->browser_W = browser_window->width();
1837             config->browser_H = browser_window->height();
1838         }
1839         if (settings_window->isVisible())
1840         {
1841             config->settings_X = settings_window->x();
1842             config->settings_Y = settings_window->y();
1843             config->settings_W = settings_window->width();
1844             config->settings_H = settings_window->height();
1845         }
1846 
1847         if (config->quitMPD_onquit)
1848         {
1849             printf ("Closing MPD, as configured\n");
1850             QProcess *proc = nullptr;
1851             proc->startDetached(config->onquit_mpd_command);
1852         }
1853 
1854         config->save_config();
1855         printf ("Thank you and goodbye!\n");
1856         qApp->quit();
1857     }
1858 
1859     ce->accept();
1860 }
1861 
1862 
on_shudown()1863 void qm_player::on_shudown()
1864 {
1865     b_really_close = true;
1866     close();
1867 }
1868 
1869 
1870 // connecting signal directly to keyPressEvent() does not work, so:
on_browser_keypress(QKeyEvent * event)1871 void qm_player::on_browser_keypress(QKeyEvent *event)
1872 {
1873     switch (event->key())
1874     {
1875         case Qt::Key_MediaPause:
1876         case Qt::Key_MediaPlay:
1877         case Qt::Key_MediaNext:
1878         case Qt::Key_MediaPrevious:
1879         case Qt::Key_MediaStop:
1880         {
1881             qm_player::keyPressEvent(event);
1882             break;
1883         }
1884         default:
1885             break;
1886     }
1887 }
1888 
keyPressEvent(QKeyEvent * event)1889 void qm_player::keyPressEvent(QKeyEvent *event)
1890 {
1891     switch (event->key())
1892     {
1893         case Qt::Key_Q:
1894         {
1895             if (event->modifiers() & Qt::ControlModifier)
1896                 on_shudown();
1897             break;
1898         }
1899         case Qt::Key_MediaPause:
1900         {
1901             printf ("Key_MediaPause pressed\n");
1902             on_signal(ID_play);
1903             break;
1904 
1905         }
1906         case Qt::Key_MediaPlay:
1907         {
1908             printf ("Key_MediaPlay pressed\n");
1909             on_signal(ID_play);
1910             break;
1911 
1912         }
1913         case Qt::Key_MediaNext:
1914         {
1915             printf ("Key_MediaNext pressed\n");
1916             on_signal(ID_next);
1917             break;
1918 
1919         }
1920         case Qt::Key_MediaPrevious:
1921         {
1922             printf ("Key_MediaPrevious pressed\n");
1923             on_signal(ID_prev);
1924             break;
1925 
1926         }
1927         case Qt::Key_MediaStop:
1928         {
1929             printf ("Key_MediaStop pressed\n");
1930             on_signal(ID_stop);
1931             break;
1932 
1933         }
1934         default:
1935             QMainWindow::keyPressEvent(event);
1936     }
1937 }
1938 
1939 ///////////////// D&D Stuff ///////////////////////////////
dragEnterEvent(QDragEnterEvent * e)1940 void qm_player::dragEnterEvent(QDragEnterEvent *e)
1941 {
1942     if (config->mpd_socket_conn && e->source() == nullptr &&  e->mimeData()->hasUrls())
1943         e->accept();
1944     else
1945         e->ignore();
1946 }
1947 
1948 
dragMoveEvent(QDragMoveEvent * e)1949 void qm_player::dragMoveEvent(QDragMoveEvent *e)
1950 {
1951     if (config->mpd_socket_conn && e->source() == nullptr &&  e->mimeData()->hasUrls())
1952         e->accept();
1953     else
1954         e->ignore();
1955 }
1956 
1957 
dragLeaveEvent(QDragLeaveEvent * e)1958 void qm_player::dragLeaveEvent(QDragLeaveEvent *e)
1959 {
1960     e->accept();
1961 }
1962 
1963 
dropEvent(QDropEvent * e)1964 void qm_player::dropEvent(QDropEvent *e)
1965 {
1966     if (config->mpd_socket_conn && e->source() == nullptr &&  e->mimeData()->hasUrls())
1967         browser_window->plist_view->on_open_with_droprequest(e);
1968 
1969     e->ignore();
1970 }
1971 ///////////////// end D&D Stuff ///////////////////////////
1972 
1973 
1974 // get coverart from tag
getTagImage(QString qs_file)1975 QImage qm_player::getTagImage(QString qs_file)
1976 {
1977 
1978     QImage image = QImage();
1979 
1980     // check if file (still) exists
1981     QFile chkfile(qs_file);
1982     if (!chkfile.exists())
1983     {
1984         printf ("image from TAG: file not found\n");
1985         return image;
1986     }
1987 
1988     //QByteArray byteArray = qs_file.toUtf8();
1989     //const char* file = byteArray.constData();
1990 
1991     const char* file = qs_file.toUtf8().constData();
1992 
1993     if ( qs_file.endsWith(".mp3",  Qt::CaseInsensitive) )
1994     {
1995         TagLib::MPEG::File mpgfile(file);
1996         if (mpgfile.isValid())
1997         {
1998             if (mpgfile.ID3v2Tag()) // has ID3v2 tag
1999             {
2000                 TagLib::ID3v2::FrameList flist = mpgfile.ID3v2Tag()->frameList("APIC");
2001 
2002                 if(!flist.isEmpty())
2003                 {
2004                     TagLib::ID3v2::AttachedPictureFrame *pframe =
2005                         static_cast<TagLib::ID3v2::AttachedPictureFrame *>(flist.front());
2006 
2007                     if ( image.loadFromData(reinterpret_cast<const uchar *>(pframe->picture().data()), static_cast<int>(pframe->picture().size()) ) )
2008                     {
2009                         //printf ("Cover art from mp3 tag\n");
2010                         return image;
2011                     }
2012                 }
2013             }
2014             else
2015             if( mpgfile.APETag())
2016             {
2017                 TagLib::APE::Tag* tag = static_cast<TagLib::APE::Tag *>(mpgfile.APETag());
2018                 const TagLib::APE::ItemListMap& listMap = tag->itemListMap();
2019 
2020                 if (listMap.contains("COVER ART (FRONT)"))
2021                 {
2022                    const TagLib::ByteVector nullStringTerminator(1, 0);
2023 
2024                    TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
2025                    int pos = item.find(nullStringTerminator);	// Skip the filename
2026 
2027                    if (++pos > 0)
2028                    {
2029                        const TagLib::ByteVector & picvect = item.mid(static_cast<uint>(pos));
2030                        QByteArray image_data( picvect.data(), static_cast<int>(picvect.size()) );
2031                        if (image.loadFromData(image_data))
2032                        {
2033                          //printf ("Cover art from ape tag\n");
2034                          return image;
2035                        }
2036                    }
2037                 }
2038             }
2039         }
2040     }
2041     else
2042     if ( qs_file.endsWith(".ogg",  Qt::CaseInsensitive) ||
2043          qs_file.endsWith(".oga",  Qt::CaseInsensitive)  )
2044     {
2045         TagLib::Ogg::Vorbis::File oggfile(file);
2046         if(oggfile.isValid())
2047         {
2048             if (oggfile.tag()) // has XiphComment tag
2049             {
2050                 TagLib::Ogg::XiphComment *m_tag = static_cast<TagLib::Ogg::XiphComment *>(oggfile.tag());
2051                 /////// First we try the flac-type picturelist
2052                 #if taglib_piclist
2053                 TagLib::List<TagLib::FLAC::Picture *> picList = m_tag->pictureList();
2054 
2055                 if(!picList.isEmpty())
2056                 {
2057                     TagLib::FLAC::Picture* fpic = picList[0];
2058 
2059                     QByteArray image_data( fpic->data().data(), static_cast<int>(fpic->data().size()) );
2060 
2061                     if (image.loadFromData(image_data))
2062                     {
2063                         //printf ("Cover art from ogg-flac tag\n");
2064                         return image;
2065                     }
2066                 }
2067                 #endif
2068 
2069                 /////// If the above fails we try the fieldListMap
2070 
2071                 TagLib::StringList block;
2072 
2073                 const TagLib::Ogg::FieldListMap& flMap = m_tag->fieldListMap();
2074 
2075                 if( flMap.contains( "METADATA_BLOCK_PICTURE" ) )
2076                 {
2077                     block = m_tag->fieldListMap()[ "METADATA_BLOCK_PICTURE" ];
2078                 }
2079                 else
2080                 if( flMap.contains( "COVERART" ) )
2081                 {
2082                      block = m_tag->fieldListMap()[ "COVERART" ];
2083                 }
2084 
2085                 if (!block.isEmpty())
2086                 {
2087 
2088                     for( TagLib::StringList::ConstIterator i = block.begin(); i != block.end(); ++i )
2089                     {
2090                         QByteArray data( QByteArray::fromBase64( i->to8Bit().c_str() ) );
2091                         TagLib::ByteVector tdata( data.data(), static_cast<uint>(data.size()) );
2092 
2093                         TagLib::FLAC::Picture fpic;
2094 
2095                         if(!fpic.parse(tdata))
2096                         {
2097                             continue;
2098                         }
2099 
2100                         QByteArray image_data( fpic.data().data(), static_cast<int>(fpic.data().size()) );
2101 
2102                         if (image.loadFromData(image_data))
2103                         {
2104                             //printf ("Cover art from ogg tag\n");
2105                             return image;
2106                         }
2107                     }
2108                 }
2109 
2110             }
2111 
2112         }
2113     }
2114     else
2115     if ( qs_file.endsWith(".flac",  Qt::CaseInsensitive) )
2116     {
2117         TagLib::FLAC::File flacfile(file);
2118         if (flacfile.isValid())
2119         {
2120             if (flacfile.ID3v2Tag()) // has ID3v2 tag
2121             {
2122                 TagLib::ID3v2::FrameList flist = flacfile.ID3v2Tag()->frameList("APIC");
2123 
2124                 if(!flist.isEmpty())
2125                 {
2126                     TagLib::ID3v2::AttachedPictureFrame *pframe =
2127                         static_cast<TagLib::ID3v2::AttachedPictureFrame *>(flist.front());
2128 
2129                     if ( image.loadFromData(reinterpret_cast<const uchar *>(pframe->picture().data()), static_cast<int>(pframe->picture().size()) ) )
2130                     {
2131                         //printf ("Cover art from flac (ID3v2) tag\n");
2132                         return image;
2133                     }
2134                 }
2135             }
2136 
2137             #if taglib_piclist
2138             if (flacfile.tag()) // has flac tag
2139             {
2140                 const TagLib::List<TagLib::FLAC::Picture*>& picList = flacfile.pictureList();
2141 
2142                 if (!picList.isEmpty())
2143                 {
2144                     TagLib::FLAC::Picture* fpic = picList[0];
2145 
2146                     QByteArray image_data( fpic->data().data(), static_cast<int>(fpic->data().size()) );
2147 
2148                     if (image.loadFromData(image_data))
2149                     {
2150                         //printf ("Cover art from flac tag\n");
2151                         return image;
2152                     }
2153                 }
2154             }
2155             #endif
2156         }
2157     }
2158     else
2159     if ( qs_file.endsWith(".mp4",  Qt::CaseInsensitive) ||
2160          qs_file.endsWith(".m4a",  Qt::CaseInsensitive) ||
2161          qs_file.endsWith(".aac",  Qt::CaseInsensitive)  )
2162     {
2163         TagLib::MP4::File mp4file(file);
2164         if (mp4file.isValid())
2165         {
2166             if (mp4file.tag()) // has MP4 tag
2167             {
2168                 TagLib::MP4::Tag *tag = static_cast<TagLib::MP4::Tag *>(mp4file.tag());
2169                 TagLib::MP4::ItemListMap itemsListMap = tag->itemListMap();
2170                 if (tag->itemListMap().contains("covr"))
2171                 {
2172                     TagLib::MP4::Item coverItem = itemsListMap["covr"];
2173                     TagLib::MP4::CoverArtList coverArtList = coverItem.toCoverArtList();
2174                     TagLib::MP4::CoverArt coverArt = coverArtList.front();
2175                     if ( image.loadFromData(reinterpret_cast<const uchar *>(coverArt.data().data()), static_cast<int>(coverArt.data().size())) )
2176                     {
2177                         //printf ("Cover art from mp4 tag\n");
2178                         return image;
2179                     }
2180                 }
2181             }
2182         }
2183     }
2184     else
2185     if ( qs_file.endsWith(".mpc",  Qt::CaseInsensitive) ||
2186          qs_file.endsWith(".mpp",  Qt::CaseInsensitive)  )
2187     {
2188         TagLib::MPC::File mpcfile(file);
2189         if (mpcfile.isValid())
2190         {
2191             if( mpcfile.APETag())
2192             {
2193                 TagLib::APE::Tag* tag = static_cast<TagLib::APE::Tag *>(mpcfile.APETag());
2194                 const TagLib::APE::ItemListMap& listMap = tag->itemListMap();
2195 
2196                 if (listMap.contains("COVER ART (FRONT)"))
2197                 {
2198                    const TagLib::ByteVector nullStringTerminator(1, 0);
2199 
2200                    TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
2201                    int pos = item.find(nullStringTerminator);	// Skip the filename
2202 
2203                    if (++pos > 0)
2204                    {
2205                        const TagLib::ByteVector & picvect = item.mid(static_cast<uint>(pos));
2206                        QByteArray image_data( picvect.data(), static_cast<int>(picvect.size()) );
2207                        if (image.loadFromData(image_data))
2208                        {
2209                          //printf ("Cover art from mpc (ape) tag\n");
2210                          return image;
2211                        }
2212                    }
2213                 }
2214             }
2215         }
2216     }
2217     else
2218     if ( qs_file.endsWith(".wv",  Qt::CaseInsensitive) )
2219     {
2220         TagLib::WavPack::File wvpfile(file);
2221         if (wvpfile.isValid())
2222         {
2223             if( wvpfile.APETag())
2224             {
2225                 TagLib::APE::Tag* tag = static_cast<TagLib::APE::Tag *>(wvpfile.APETag());
2226                 const TagLib::APE::ItemListMap& listMap = tag->itemListMap();
2227 
2228                 if (listMap.contains("COVER ART (FRONT)"))
2229                 {
2230                     printf ("APE tag  COVER ART found\n");
2231                    const TagLib::ByteVector nullStringTerminator(1, 0);
2232 
2233                    TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
2234                    int pos = item.find(nullStringTerminator);	// Skip the filename
2235 
2236                    if (++pos > 0)
2237                    {
2238                        const TagLib::ByteVector & picvect = item.mid(static_cast<uint>(pos));
2239                        QByteArray image_data( picvect.data(), static_cast<int>(picvect.size()) );
2240                        if (image.loadFromData(image_data))
2241                        {
2242                          //printf ("Cover art from wv (ape) tag\n");
2243                          return image;
2244                        }
2245                    }
2246                 }
2247             }
2248         }
2249     }
2250     else
2251     if ( qs_file.endsWith(".ape",  Qt::CaseInsensitive) )
2252     {
2253         TagLib::WavPack::File apefile(file);
2254         if (apefile.isValid())
2255         {
2256             if( apefile.APETag())
2257             {
2258                 TagLib::APE::Tag* tag = static_cast<TagLib::APE::Tag *>(apefile.APETag());
2259                 const TagLib::APE::ItemListMap& listMap = tag->itemListMap();
2260 
2261                 /* // DEBUG: List all tags
2262                 for( TagLib::APE::ItemListMap::ConstIterator it = listMap.begin(); it != listMap.end(); ++it )
2263                 {
2264                     QString value = TStringToQString( it->first );
2265                     const char* entry = value.toUtf8().constData();
2266                     printf ("Ape_tag: [%s]\n",entry);
2267                 }  */
2268 
2269                 if (listMap.contains("COVER ART (FRONT)"))
2270                 {
2271                    const TagLib::ByteVector nullStringTerminator(1, 0);
2272 
2273                    TagLib::ByteVector item = listMap["COVER ART (FRONT)"].value();
2274                    int pos = item.find(nullStringTerminator);	// Skip the filename
2275 
2276                    if (++pos > 0)
2277                    {
2278                        const TagLib::ByteVector & picvect = item.mid(static_cast<uint>(pos));
2279                        QByteArray image_data( picvect.data(), static_cast<int>(picvect.size()) );
2280                        if (image.loadFromData(image_data))
2281                        {
2282                          //printf ("Cover art from ape tag\n");
2283                          return image;
2284                        }
2285                    }
2286                 }
2287             }
2288         }
2289     }
2290     else
2291     if ( qs_file.endsWith(".asf",  Qt::CaseInsensitive) )
2292     {
2293         TagLib::ASF::File asffile(file);
2294         if (asffile.isValid())
2295         {
2296             if (asffile.tag()) // has asf tag
2297             {
2298                 TagLib::ASF::Tag *tag = static_cast<TagLib::ASF::Tag *>(asffile.tag());
2299                 const TagLib::ASF::AttributeListMap& attrListMap = tag->attributeListMap();
2300                 if (attrListMap.contains("WM/Picture"))
2301                 {
2302                     const TagLib::ASF::AttributeList& attrList = attrListMap["WM/Picture"];
2303 
2304                     if (!attrList.isEmpty())
2305                     {
2306                         //grab the first cover.
2307                         TagLib::ASF::Picture pic = attrList[0].toPicture();
2308                         if (pic.isValid())
2309                         {
2310                             const QByteArray image_data( pic.picture().data(), static_cast<int>(pic.picture().size()) );
2311 
2312                             if (image.loadFromData(image_data))
2313                             {
2314                                 //printf ("Cover art from asf tag\n");
2315                                 return image;
2316                             }
2317                         }
2318                     }
2319                 }
2320             }
2321         }
2322     }
2323 
2324     return image;
2325 }
2326 /*
2327 bool qm_player::eventFilter( QObject* ob, QEvent *event )
2328 {
2329     printf ("DEBUG1 evenFilter systray\n"); // never happens
2330 
2331     QKeyEvent *ke = static_cast<QKeyEvent *>(event);
2332     int keyValue = ke->key();
2333 
2334     if(event->type() == QEvent::KeyPress )
2335     {
2336       printf ("KeyPressed: %i\n", keyValue);
2337       // Qt::Key_0  Qt::Key_1 e Qt::Key_2
2338       return true;
2339     }
2340 
2341     return QObject::eventFilter(ob, event);
2342 }
2343 */
~qm_player()2344 qm_player::~qm_player()
2345 {
2346     delete (mpdCom);
2347     delete (browser_window);
2348     delete (settings_window);
2349     delete (config);
2350     delete (the_trayicon);
2351     delete (ds_progress);
2352     delete (lb_time);
2353     delete (vol_slider);
2354 }
2355