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 = " <b>" + artist + "</b> ";
765 QString title_tip = " <i>" + title + " </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("[»]");
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