diff --git a/src/aboutDialog.cpp b/src/aboutDialog.cpp index 4b5bb52..a57b665 100644 --- a/src/aboutDialog.cpp +++ b/src/aboutDialog.cpp @@ -74,7 +74,7 @@ NAboutDialog::NAboutDialog(QWidget *parent) : QDialog(parent) QSvgWidget svgWidget(":icon.svg"); svgWidget.setStyleSheet("background: transparent"); svgWidget.resize(96, 96); - iconLabel->setPixmap(svgWidget.grab()); + iconLabel->setPixmap(QPixmap::grabWidget(&svgWidget)); QHBoxLayout *iconLayout = new QHBoxLayout; iconLayout->addStretch(); diff --git a/src/action.cpp b/src/action.cpp index 8c52d4d..ccb08d7 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -23,7 +23,7 @@ bool NAction::isEnabled() const void NAction::setEnabled(bool enable) { - for (QxtGlobalShortcut *shortcut : m_globalShortcuts) { + foreach (QxtGlobalShortcut *shortcut, m_globalShortcuts) { shortcut->setEnabled(enable); } QAction::setEnabled(enable); @@ -47,7 +47,7 @@ QList NAction::sequences() const QStringList NAction::shortcuts() const { QStringList shortcuts; - for (const QKeySequence &seq : sequences()) { + foreach (const QKeySequence &seq, sequences()) { shortcuts << seq.toString(); } return shortcuts; @@ -61,7 +61,7 @@ void NAction::setSequences(const QList &sequences) void NAction::setShortcuts(const QStringList &shortcuts) { QList sequences; - for (const QString &str : shortcuts) { + foreach (const QString &str, shortcuts) { sequences << QKeySequence(str); } setSequences(sequences); @@ -70,7 +70,7 @@ void NAction::setShortcuts(const QStringList &shortcuts) QList NAction::globalSequences() const { QList sequences; - for (QxtGlobalShortcut *shortcut : m_globalShortcuts) { + foreach (QxtGlobalShortcut *shortcut, m_globalShortcuts) { sequences << shortcut->shortcut(); } return sequences; @@ -79,7 +79,7 @@ QList NAction::globalSequences() const QStringList NAction::globalShortcuts() const { QStringList shortcuts; - for (const QKeySequence &seq : globalSequences()) { + foreach (const QKeySequence &seq, globalSequences()) { shortcuts << seq.toString(); } return shortcuts; @@ -87,14 +87,14 @@ QStringList NAction::globalShortcuts() const void NAction::setGlobalSequences(const QList &sequences) { - for (QxtGlobalShortcut *shortcut : m_globalShortcuts) { + foreach (QxtGlobalShortcut *shortcut, m_globalShortcuts) { delete shortcut; } m_globalShortcuts.clear(); - for (const QKeySequence &seq : sequences) { + foreach (const QKeySequence &seq, sequences) { QxtGlobalShortcut *s = new QxtGlobalShortcut(this); - connect(s, &QxtGlobalShortcut::activated, this, &QAction::trigger); + connect(s, SIGNAL(activated()), this, SIGNAL(triggered())); s->setShortcut(seq); m_globalShortcuts << s; } @@ -103,8 +103,14 @@ void NAction::setGlobalSequences(const QList &sequences) void NAction::setGlobalShortcuts(const QStringList &shortcuts) { QList sequences; - for (const QString &str : shortcuts) { - sequences << QKeySequence(str); + foreach (const QString &str, shortcuts) { + // Qt4: Don't create shortcuts for empty or invalid strings + if (!str.isEmpty() && str != "@Invalid()") { + QKeySequence seq(str); + if (!seq.isEmpty()) { + sequences << seq; + } + } } setGlobalSequences(sequences); } diff --git a/src/action.h b/src/action.h index 700a138..f2534ef 100644 --- a/src/action.h +++ b/src/action.h @@ -25,7 +25,9 @@ class NAction : public QAction Q_OBJECT public: - using QAction::QAction; + NAction(QObject *parent = 0) : QAction(parent), m_isCustomizable(false) {} + NAction(const QString &text, QObject *parent = 0) : QAction(text, parent), m_isCustomizable(false) {} + NAction(const QIcon &icon, const QString &text, QObject *parent = 0) : QAction(icon, text, parent), m_isCustomizable(false) {} bool isEnabled() const; void setEnabled(bool enable); @@ -44,7 +46,7 @@ public: void setGlobalShortcuts(const QStringList &shortcuts); private: - bool m_isCustomizable = false; + bool m_isCustomizable; QList m_globalShortcuts; }; diff --git a/src/actionManager.cpp b/src/actionManager.cpp index 3103eb4..8fa5ee7 100644 --- a/src/actionManager.cpp +++ b/src/actionManager.cpp @@ -16,6 +16,7 @@ #include "actionManager.h" #include "action.h" +#include "common.h" #include "coverWidget.h" #include "mainWindow.h" #include "playbackEngineInterface.h" @@ -26,6 +27,7 @@ #include "trash.h" #include +#include #include #include #include @@ -65,7 +68,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) showHideAction->setObjectName("ShowHideAction"); showHideAction->setStatusTip(tr("Toggle window visibility")); showHideAction->setCustomizable(true); - connect(showHideAction, &NAction::triggered, player, &NPlayer::toggleWindowVisibility); + connect(showHideAction, SIGNAL(triggered()), player, SLOT(toggleWindowVisibility())); m_trayIconMenu->addAction(showHideAction); } @@ -79,8 +82,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) playAction->setObjectName("PlayAction"); playAction->setStatusTip(tr("Start playback")); playAction->setCustomizable(true); - connect(playAction, &NAction::triggered, player->playbackEngine(), - &NPlaybackEngineInterface::play); + connect(playAction, SIGNAL(triggered()), player->playbackEngine(), + SLOT(play())); m_trayIconMenu->addAction(playAction); controlsMenu->addAction(playAction); } @@ -93,8 +96,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) pauseAction->setObjectName("PauseAction"); pauseAction->setStatusTip(tr("Pause playback")); pauseAction->setCustomizable(true); - connect(pauseAction, &NAction::triggered, player->playbackEngine(), - &NPlaybackEngineInterface::pause); + connect(pauseAction, SIGNAL(triggered()), player->playbackEngine(), + SLOT(pause())); m_trayIconMenu->addAction(pauseAction); controlsMenu->addAction(pauseAction); } @@ -107,7 +110,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) playPauseAction->setObjectName("PlayPauseAction"); playPauseAction->setStatusTip(tr("Toggle playback")); playPauseAction->setCustomizable(true); - connect(playPauseAction, &NAction::triggered, player, &NPlayer::playPause); + connect(playPauseAction, SIGNAL(triggered()), player, SLOT(playPause())); m_trayIconMenu->addAction(playPauseAction); controlsMenu->addAction(playPauseAction); } @@ -120,8 +123,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) stopAction->setObjectName("StopAction"); stopAction->setStatusTip(tr("Stop playback")); stopAction->setCustomizable(true); - connect(stopAction, &NAction::triggered, player->playbackEngine(), - &NPlaybackEngineInterface::stop); + connect(stopAction, SIGNAL(triggered()), player->playbackEngine(), + SLOT(stop())); m_trayIconMenu->addAction(stopAction); controlsMenu->addAction(stopAction); } @@ -134,8 +137,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) prevAction->setObjectName("PrevAction"); prevAction->setStatusTip(tr("Play previous track in playlist")); prevAction->setCustomizable(true); - connect(prevAction, &NAction::triggered, player->playlistWidget(), - &NPlaylistWidget::playPrevItem); + connect(prevAction, SIGNAL(triggered()), player->playlistWidget(), + SLOT(playPrevItem())); m_trayIconMenu->addAction(prevAction); controlsMenu->addAction(prevAction); } @@ -148,8 +151,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) nextAction->setObjectName("NextAction"); nextAction->setStatusTip(tr("Play next track in playlist")); nextAction->setCustomizable(true); - connect(nextAction, &NAction::triggered, player->playlistWidget(), - &NPlaylistWidget::playNextItem); + connect(nextAction, SIGNAL(triggered()), player->playlistWidget(), + SLOT(playNextItem())); m_trayIconMenu->addAction(nextAction); controlsMenu->addAction(nextAction); } @@ -161,7 +164,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *addFilesAction = new NAction(QIcon::fromTheme("add", winIcons.value(171)), tr("Add Files..."), player); addFilesAction->setShortcut(QKeySequence("Ctrl+O")); - connect(addFilesAction, &NAction::triggered, player, &NPlayer::showOpenFileDialog); + connect(addFilesAction, SIGNAL(triggered()), player, SLOT(showOpenFileDialog())); m_contextMenu->addAction(addFilesAction); fileMenu->addAction(addFilesAction); } @@ -170,7 +173,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *addDirAction = new NAction(QIcon::fromTheme("folder-add", winIcons.value(3)), tr("Add Directory..."), player); addDirAction->setShortcut(QKeySequence("Ctrl+Shift+O")); - connect(addDirAction, &NAction::triggered, player, &NPlayer::showOpenDirDialog); + connect(addDirAction, SIGNAL(triggered()), player, SLOT(showOpenDirDialog())); m_contextMenu->addAction(addDirAction); fileMenu->addAction(addDirAction); } @@ -180,7 +183,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) winIcons.value(175)), tr("Save Playlist..."), player); savePlaylistAction->setShortcut(QKeySequence("Ctrl+S")); - connect(savePlaylistAction, &NAction::triggered, player, &NPlayer::showSavePlaylistDialog); + connect(savePlaylistAction, SIGNAL(triggered()), player, SLOT(showSavePlaylistDialog())); m_contextMenu->addAction(savePlaylistAction); fileMenu->addAction(savePlaylistAction); } @@ -192,7 +195,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *preferencesAction = new NAction(QIcon::fromTheme("configure", winIcons.value(109)), tr("Preferences..."), player); preferencesAction->setShortcut(QKeySequence("Ctrl+P")); - connect(preferencesAction, &NAction::triggered, player, &NPlayer::showPreferencesDialog); + connect(preferencesAction, SIGNAL(triggered()), player, SLOT(showPreferencesDialog())); m_trayIconMenu->addAction(preferencesAction); m_contextMenu->addAction(preferencesAction); fileMenu->addAction(preferencesAction); @@ -204,10 +207,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *showCoverAction = new NAction(tr("Show Cover Art"), player); showCoverAction->setCheckable(true); showCoverAction->setObjectName("ShowCoverAction"); - connect(showCoverAction, &NAction::toggled, [player](bool checked) { - player->settings()->setValue("ShowCoverArt", checked); - player->coverWidget()->setVisible(checked); - }); + connect(showCoverAction, SIGNAL(toggled(bool)), this, SLOT(on_showCoverAction_toggled(bool))); showCoverAction->setChecked(player->settings()->value("ShowCoverArt").toBool()); windowSubMenu->addAction(showCoverAction); windowMenu->addAction(showCoverAction); @@ -217,8 +217,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *showPlaybackControlsAction = new NAction(tr("Show Playback Controls"), player); showPlaybackControlsAction->setCheckable(true); showPlaybackControlsAction->setObjectName("ShowPlaybackControls"); - connect(showPlaybackControlsAction, &NAction::toggled, player->mainWindow(), - &NMainWindow::showPlaybackControls); + connect(showPlaybackControlsAction, SIGNAL(toggled(bool)), player->mainWindow(), + SLOT(showPlaybackControls(bool))); showPlaybackControlsAction->setChecked( player->settings()->value("ShowPlaybackControls").toBool()); windowSubMenu->addAction(showPlaybackControlsAction); @@ -228,7 +228,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) { NAction *aboutAction = new NAction(QIcon::fromTheme("help", winIcons.value(76)), tr("About"), player); - connect(aboutAction, &NAction::triggered, player, &NPlayer::showAboutDialog); + connect(aboutAction, SIGNAL(triggered()), player, SLOT(showAboutDialog())); m_contextMenu->addAction(aboutAction); fileMenu->addAction(aboutAction); } @@ -239,8 +239,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *exitAction = new NAction(QIcon::fromTheme("exit", winIcons.value(259)), tr("Exit"), player); exitAction->setShortcut(QKeySequence("Ctrl+Q")); - connect(exitAction, &NAction::triggered, QCoreApplication::instance(), - &QCoreApplication::quit); + connect(exitAction, SIGNAL(triggered()), QCoreApplication::instance(), + SLOT(quit())); m_contextMenu->addAction(exitAction); m_trayIconMenu->addAction(exitAction); fileMenu->addAction(exitAction); @@ -250,15 +250,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *playingOnTopAction = new NAction(tr("On Top During Playback"), player); playingOnTopAction->setCheckable(true); playingOnTopAction->setObjectName("PlayingOnTopAction"); - connect(playingOnTopAction, &NAction::toggled, [player](bool checked) { - player->settings()->setValue("WhilePlayingOnTop", checked); - - bool alwaysOnTop = player->settings()->value("AlwaysOnTop").toBool(); - if (!alwaysOnTop) { - player->mainWindow()->setOnTop(checked && player->playbackEngine()->state() == - N::PlaybackPlaying); - } - }); + connect(playingOnTopAction, SIGNAL(toggled(bool)), this, SLOT(on_playingOnTopAction_toggled(bool))); playingOnTopAction->setChecked(player->settings()->value("WhilePlayingOnTop").toBool()); windowSubMenu->addAction(playingOnTopAction); windowMenu->addAction(playingOnTopAction); @@ -268,14 +260,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *alwaysOnTopAction = new NAction(tr("Always On Top"), player); alwaysOnTopAction->setCheckable(true); alwaysOnTopAction->setObjectName("AlwaysOnTopAction"); - connect(alwaysOnTopAction, &NAction::toggled, [player](bool checked) { - player->settings()->setValue("AlwaysOnTop", checked); - - bool whilePlaying = player->settings()->value("WhilePlayingOnTop").toBool(); - if (!whilePlaying || player->playbackEngine()->state() != N::PlaybackPlaying) { - player->mainWindow()->setOnTop(checked); - } - }); + connect(alwaysOnTopAction, SIGNAL(toggled(bool)), this, SLOT(on_alwaysOnTopAction_toggled(bool))); alwaysOnTopAction->setChecked(player->settings()->value("AlwaysOnTop").toBool()); windowSubMenu->addAction(alwaysOnTopAction); windowMenu->addAction(alwaysOnTopAction); @@ -286,8 +271,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) fullScreenAction->setStatusTip(tr("Hide all controls except waveform")); fullScreenAction->setObjectName("FullScreenAction"); fullScreenAction->setCustomizable(true); - connect(fullScreenAction, &NAction::triggered, player->mainWindow(), - &NMainWindow::toggleFullScreen); + connect(fullScreenAction, SIGNAL(triggered()), player->mainWindow(), + SLOT(toggleFullScreen())); windowSubMenu->addAction(fullScreenAction); windowMenu->addAction(fullScreenAction); } @@ -297,8 +282,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) shufflePlaylistAction->setObjectName("ShufflePlaylistAction"); shufflePlaylistAction->setStatusTip(tr("Shuffle items in playlist")); shufflePlaylistAction->setCustomizable(true); - connect(shufflePlaylistAction, &NAction::triggered, player->playlistWidget(), - &NPlaylistWidget::shufflePlaylist); + connect(shufflePlaylistAction, SIGNAL(triggered()), player->playlistWidget(), + SLOT(shufflePlaylist())); playlistSubMenu->addAction(shufflePlaylistAction); controlsPlaylistSubMenu->addAction(shufflePlaylistAction); } @@ -309,10 +294,10 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) repeatPlaylistAction->setObjectName("RepeatPlaylistAction"); repeatPlaylistAction->setStatusTip(tr("Toggle current item repeat")); repeatPlaylistAction->setCustomizable(true); - connect(repeatPlaylistAction, &NAction::triggered, player->playlistWidget(), - &NPlaylistWidget::setRepeatMode); - connect(player->playlistWidget(), &NPlaylistWidget::repeatModeChanged, repeatPlaylistAction, - &NAction::setChecked); + connect(repeatPlaylistAction, SIGNAL(triggered(bool)), player->playlistWidget(), + SLOT(setRepeatMode(bool))); + connect(player->playlistWidget(), SIGNAL(repeatModeChanged(bool)), repeatPlaylistAction, + SLOT(setChecked(bool))); repeatPlaylistAction->setChecked(player->settings()->value("Repeat").toBool()); playlistSubMenu->addAction(repeatPlaylistAction); controlsPlaylistSubMenu->addAction(repeatPlaylistAction); @@ -322,8 +307,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) NAction *loopPlaylistAction = new NAction(tr("Loop playlist"), player); loopPlaylistAction->setCheckable(true); loopPlaylistAction->setObjectName("LoopPlaylistAction"); - connect(loopPlaylistAction, &NAction::triggered, - [player](bool checked) { player->settings()->setValue("LoopPlaylist", checked); }); + connect(loopPlaylistAction, SIGNAL(triggered(bool)), this, SLOT(on_loopPlaylistAction_triggered(bool))); loopPlaylistAction->setChecked(player->settings()->value("LoopPlaylist").toBool()); playlistSubMenu->addAction(loopPlaylistAction); controlsPlaylistSubMenu->addAction(loopPlaylistAction); @@ -335,8 +319,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) scrollToItemPlaylistAction->setStatusTip( tr("Automatically scroll playlist to currently playing item")); scrollToItemPlaylistAction->setObjectName("ScrollToItemPlaylistAction"); - connect(scrollToItemPlaylistAction, &NAction::triggered, - [player](bool checked) { player->settings()->setValue("ScrollToItem", checked); }); + connect(scrollToItemPlaylistAction, SIGNAL(triggered(bool)), this, SLOT(on_scrollToItemPlaylistAction_triggered(bool))); scrollToItemPlaylistAction->setChecked(player->settings()->value("ScrollToItem").toBool()); playlistSubMenu->addAction(scrollToItemPlaylistAction); controlsPlaylistSubMenu->addAction(scrollToItemPlaylistAction); @@ -347,8 +330,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) player); nextFileEnableAction->setCheckable(true); nextFileEnableAction->setObjectName("NextFileEnableAction"); - connect(nextFileEnableAction, &NAction::triggered, - [player](bool checked) { player->settings()->setValue("LoadNext", checked); }); + connect(nextFileEnableAction, SIGNAL(triggered(bool)), this, SLOT(on_nextFileEnableAction_triggered(bool))); nextFileEnableAction->setChecked(player->settings()->value("LoadNext").toBool()); playlistSubMenu->addAction(nextFileEnableAction); controlsPlaylistSubMenu->addAction(nextFileEnableAction); @@ -357,9 +339,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) new NAction(QString::fromUtf8(" ├ %1 ↓").arg(tr("By Name")), player); nextFileByNameAscdAction->setCheckable(true); nextFileByNameAscdAction->setObjectName("NextFileByNameAscdAction"); - connect(nextFileByNameAscdAction, &NAction::triggered, [player](bool checked) { - player->settings()->setValue("LoadNextSort", (int)QDir::Name); - }); + connect(nextFileByNameAscdAction, SIGNAL(triggered(bool)), this, SLOT(on_nextFileByNameAscdAction_triggered(bool))); playlistSubMenu->addAction(nextFileByNameAscdAction); controlsPlaylistSubMenu->addAction(nextFileByNameAscdAction); @@ -367,9 +347,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) new NAction(QString::fromUtf8(" ├ %1 ↑").arg(tr("By Name")), player); nextFileByNameDescAction->setCheckable(true); nextFileByNameDescAction->setObjectName("NextFileByNameDescAction"); - connect(nextFileByNameDescAction, &NAction::triggered, [player](bool checked) { - player->settings()->setValue("LoadNextSort", (int)(QDir::Name | QDir::Reversed)); - }); + connect(nextFileByNameDescAction, SIGNAL(triggered(bool)), this, SLOT(on_nextFileByNameDescAction_triggered(bool))); playlistSubMenu->addAction(nextFileByNameDescAction); controlsPlaylistSubMenu->addAction(nextFileByNameDescAction); @@ -377,9 +355,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) new NAction(QString::fromUtf8(" ├ %1 ↓").arg(tr("By Date")), player); nextFileByDateAscd->setCheckable(true); nextFileByDateAscd->setObjectName("NextFileByDateAscd"); - connect(nextFileByDateAscd, &NAction::triggered, [player](bool checked) { - player->settings()->setValue("LoadNextSort", (int)(QDir::Time | QDir::Reversed)); - }); + connect(nextFileByDateAscd, SIGNAL(triggered(bool)), this, SLOT(on_nextFileByDateAscdAction_triggered(bool))); playlistSubMenu->addAction(nextFileByDateAscd); controlsPlaylistSubMenu->addAction(nextFileByDateAscd); @@ -387,9 +363,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) new NAction(QString::fromUtf8(" └ %1 ↑").arg(tr("By Date")), player); nextFileByDateDesc->setCheckable(true); nextFileByDateDesc->setObjectName("NextFileByDateDesc"); - connect(nextFileByDateDesc, &NAction::triggered, [player](bool checked) { - player->settings()->setValue("LoadNextSort", (int)(QDir::Time)); - }); + connect(nextFileByDateDesc, SIGNAL(triggered(bool)), this, SLOT(on_nextFileByDateDescAction_triggered(bool))); playlistSubMenu->addAction(nextFileByDateDesc); controlsPlaylistSubMenu->addAction(nextFileByDateDesc); @@ -417,18 +391,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) revealAction->setObjectName("RevealInFileManagerAction"); revealAction->setStatusTip(tr("Open file manager for selected file")); revealAction->setCustomizable(true); - connect(revealAction, &NAction::triggered, [player]() { - QStringList files = player->playlistWidget()->selectedFiles(); - if (files.isEmpty()) { - return; - } - - QString error; - if (!player->revealInFileManager(files.first(), &error)) { - QMessageBox::warning(player->mainWindow(), tr("Reveal in File Manager Error"), - error, QMessageBox::Close); - } - }); + connect(revealAction, SIGNAL(triggered()), this, SLOT(on_revealAction_triggered())); m_playlistContextMenu->addAction(revealAction); } @@ -438,8 +401,8 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) removeSelectedAction->setObjectName("RemoveFromPlaylistAction"); removeSelectedAction->setStatusTip(tr("Remove selected files from playlist")); removeSelectedAction->setCustomizable(true); - connect(removeSelectedAction, &NAction::triggered, player->playlistWidget(), - &NPlaylistWidget::removeSelected); + connect(removeSelectedAction, SIGNAL(triggered()), player->playlistWidget(), + SLOT(removeSelected())); m_playlistContextMenu->addAction(removeSelectedAction); } @@ -450,15 +413,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) trashSelectedAction->setObjectName("MoveToTrashAction"); trashSelectedAction->setStatusTip(tr("Move selected files to trash bin")); trashSelectedAction->setCustomizable(true); - connect(trashSelectedAction, &NAction::triggered, [player]() { - QStringList files = player->playlistWidget()->selectedFiles(); - if (files.isEmpty()) { - return; - } - - QStringList deleted = NTrash::moveToTrash(files); - player->playlistWidget()->removeFiles(deleted); - }); + connect(trashSelectedAction, SIGNAL(triggered()), this, SLOT(on_trashSelectedAction_triggered())); m_playlistContextMenu->addAction(trashSelectedAction); } @@ -468,13 +423,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) tagEditorAction->setObjectName("TagEditorAction"); tagEditorAction->setStatusTip(tr("Open tag editor for selected file")); tagEditorAction->setCustomizable(true); - connect(tagEditorAction, &NAction::triggered, [player]() { - QStringList files = player->playlistWidget()->selectedFiles(); - if (files.isEmpty()) { - return; - } - player->showTagEditor(files.first()); - }); + connect(tagEditorAction, SIGNAL(triggered()), this, SLOT(on_tagEditorAction_triggered())); m_playlistContextMenu->addAction(tagEditorAction); } @@ -485,19 +434,13 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) jumpForwardAction->setObjectName(QString("Jump%1ForwardAction").arg(num)); jumpForwardAction->setStatusTip(tr("Make a jump forward #%1").arg(num)); jumpForwardAction->setCustomizable(true); - connect(jumpForwardAction, &NAction::triggered, [player, num]() { - qreal seconds = player->settings()->value(QString("Jump%1").arg(num)).toDouble(); - player->playbackEngine()->jump(seconds * 1000); - }); + connect(jumpForwardAction, SIGNAL(triggered()), this, SLOT(on_jumpForwardAction_triggered())); NAction *jumpBackwardsAction = new NAction(tr("Jump Backwards #%1").arg(num), player); jumpBackwardsAction->setObjectName(QString("Jump%1BackwardsAction").arg(num)); jumpBackwardsAction->setStatusTip(tr("Make a jump backwards #%1").arg(num)); jumpBackwardsAction->setCustomizable(true); - connect(jumpBackwardsAction, &NAction::triggered, [player, num]() { - qreal seconds = player->settings()->value(QString("Jump%1").arg(num)).toDouble(); - player->playbackEngine()->jump(-seconds * 1000); - }); + connect(jumpBackwardsAction, SIGNAL(triggered()), this, SLOT(on_jumpBackwardsAction_triggered())); } { @@ -505,33 +448,19 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) speedIncreaseAction->setObjectName("SpeedIncreaseAction"); speedIncreaseAction->setStatusTip(tr("Increase playback speed")); speedIncreaseAction->setCustomizable(true); - connect(speedIncreaseAction, &NAction::triggered, [player]() { - qreal newSpeed = qMax(0.01, player->playbackEngine()->speed() + - player->settings()->value("SpeedStep").toDouble()); - player->playbackEngine()->setSpeed(newSpeed); - player->showToolTip(tr("Speed: %1").arg(player->playbackEngine()->speed())); - }); + connect(speedIncreaseAction, SIGNAL(triggered()), this, SLOT(on_speedIncreaseAction_triggered())); NAction *speedDecreaseAction = new NAction(tr("Speed Decrease"), player); speedDecreaseAction->setObjectName("SpeedDecreaseAction"); speedDecreaseAction->setStatusTip(tr("Decrease playback speed")); speedDecreaseAction->setCustomizable(true); - connect(speedDecreaseAction, &NAction::triggered, [player]() { - qreal newSpeed = qMax(0.01, player->playbackEngine()->speed() - - player->settings()->value("SpeedStep").toDouble()); - player->playbackEngine()->setSpeed(newSpeed); - player->showToolTip(tr("Speed: %1").arg(player->playbackEngine()->speed())); - }); + connect(speedDecreaseAction, SIGNAL(triggered()), this, SLOT(on_speedDecreaseAction_triggered())); NAction *speedResetAction = new NAction(tr("Speed Reset"), player); speedResetAction->setObjectName("SpeedResetAction"); speedResetAction->setStatusTip(tr("Reset playback speed to 1.0")); speedResetAction->setCustomizable(true); - connect(speedResetAction, &NAction::triggered, [player]() { - qreal newSpeed = 1.0; - player->playbackEngine()->setSpeed(newSpeed); - player->showToolTip(tr("Speed: %1").arg(player->playbackEngine()->speed())); - }); + connect(speedResetAction, SIGNAL(triggered()), this, SLOT(on_speedResetAction_triggered())); } /* @@ -540,37 +469,23 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) pitchIncreaseAction->setObjectName("PitchIncreaseAction"); pitchIncreaseAction->setStatusTip(tr("Increase playback pitch")); pitchIncreaseAction->setCustomizable(true); - connect(pitchIncreaseAction, &NAction::triggered, [player]() { - qreal newPitch = qMax(0.01, player->playbackEngine()->pitch() + - player->settings()->value("PitchStep").toDouble()); - player->playbackEngine()->setPitch(newPitch); - player->showToolTip(tr("Pitch: %1").arg(player->playbackEngine()->pitch())); - }); + connect(pitchIncreaseAction, SIGNAL(triggered()), this, SLOT(on_pitchIncreaseAction_triggered())); NAction *pitchDecreaseAction = new NAction(tr("Pitch Decrease"), player); pitchDecreaseAction->setObjectName("PitchDecreaseAction"); pitchDecreaseAction->setStatusTip(tr("Decrease playback pitch")); pitchDecreaseAction->setCustomizable(true); - connect(pitchDecreaseAction, &NAction::triggered, [player]() { - qreal newPitch = qMax(0.01, player->playbackEngine()->pitch() - - player->settings()->value("PitchStep").toDouble()); - player->playbackEngine()->setPitch(newPitch); - player->showToolTip(tr("Pitch: %1").arg(player->playbackEngine()->pitch())); - }); + connect(pitchDecreaseAction, SIGNAL(triggered()), this, SLOT(on_pitchDecreaseAction_triggered())); NAction *pitchResetAction = new NAction(tr("Pitch Reset"), player); pitchResetAction->setObjectName("PitchResetAction"); pitchResetAction->setStatusTip(tr("Reset pitch to 1.0")); pitchResetAction->setCustomizable(true); - connect(pitchResetAction, &NAction::triggered, [player]() { - qreal newPitch = 1.0; - player->playbackEngine()->setPitch(newPitch); - player->showToolTip(tr("Pitch: %1").arg(player->playbackEngine()->pitch())); - }); + connect(pitchResetAction, SIGNAL(triggered()), this, SLOT(on_pitchResetAction_triggered())); } */ - for (NAction *action : m_player->findChildren()) { + foreach (NAction *action, m_player->findChildren()) { #ifdef Q_OS_MAC // remove icons for macOS: action->setIcon(QIcon()); @@ -588,7 +503,7 @@ NActionManager::NActionManager(NPlayer *player) : QObject(player) void NActionManager::saveSettings() { - for (NAction *action : m_player->findChildren()) { + foreach (NAction *action, m_player->findChildren()) { if (action->objectName().isEmpty() || !action->isCustomizable()) { continue; } @@ -612,3 +527,164 @@ QMenu *NActionManager::trayIconMenu() { return m_trayIconMenu; } + +// Slot implementations for lambdas converted for Qt4 compatibility + +void NActionManager::on_showCoverAction_toggled(bool checked) +{ + m_player->settings()->setValue("ShowCoverArt", checked); + m_player->coverWidget()->setVisible(checked); +} + +void NActionManager::on_playingOnTopAction_toggled(bool checked) +{ + m_player->settings()->setValue("WhilePlayingOnTop", checked); + + bool alwaysOnTop = m_player->settings()->value("AlwaysOnTop").toBool(); + if (!alwaysOnTop) { + m_player->mainWindow()->setOnTop(checked && m_player->playbackEngine()->state() == + N::PlaybackPlaying); + } +} + +void NActionManager::on_alwaysOnTopAction_toggled(bool checked) +{ + m_player->settings()->setValue("AlwaysOnTop", checked); + + bool whilePlaying = m_player->settings()->value("WhilePlayingOnTop").toBool(); + if (!whilePlaying || m_player->playbackEngine()->state() != N::PlaybackPlaying) { + m_player->mainWindow()->setOnTop(checked); + } +} + +void NActionManager::on_loopPlaylistAction_triggered(bool checked) +{ + m_player->settings()->setValue("LoopPlaylist", checked); +} + +void NActionManager::on_scrollToItemPlaylistAction_triggered(bool checked) +{ + m_player->settings()->setValue("ScrollToItem", checked); +} + +void NActionManager::on_nextFileEnableAction_triggered(bool checked) +{ + m_player->settings()->setValue("LoadNext", checked); +} + +void NActionManager::on_nextFileByNameAscdAction_triggered(bool checked) +{ + Q_UNUSED(checked); + m_player->settings()->setValue("LoadNextSort", (int)QDir::Name); +} + +void NActionManager::on_nextFileByNameDescAction_triggered(bool checked) +{ + Q_UNUSED(checked); + m_player->settings()->setValue("LoadNextSort", (int)(QDir::Name | QDir::Reversed)); +} + +void NActionManager::on_nextFileByDateAscdAction_triggered(bool checked) +{ + Q_UNUSED(checked); + m_player->settings()->setValue("LoadNextSort", (int)(QDir::Time | QDir::Reversed)); +} + +void NActionManager::on_nextFileByDateDescAction_triggered(bool checked) +{ + Q_UNUSED(checked); + m_player->settings()->setValue("LoadNextSort", (int)(QDir::Time)); +} + +void NActionManager::on_revealAction_triggered() +{ + QStringList files = m_player->playlistWidget()->selectedFiles(); + if (files.isEmpty()) { + return; + } + + QString error; + if (!m_player->revealInFileManager(files.first(), &error)) { + QMessageBox::warning(m_player->mainWindow(), tr("Reveal in File Manager Error"), + error, QMessageBox::Close); + } +} + +void NActionManager::on_trashSelectedAction_triggered() +{ + QStringList files = m_player->playlistWidget()->selectedFiles(); + if (files.isEmpty()) { + return; + } + + QStringList deleted = NTrash::moveToTrash(files); + m_player->playlistWidget()->removeFiles(deleted); +} + +void NActionManager::on_tagEditorAction_triggered() +{ + QStringList files = m_player->playlistWidget()->selectedFiles(); + if (files.isEmpty()) { + return; + } + + m_player->showTagEditor(files.first()); +} + +void NActionManager::on_jumpForwardAction_triggered() +{ + qint64 num = 10 * 1000; + m_player->playbackEngine()->jump(num); +} + +void NActionManager::on_jumpBackwardsAction_triggered() +{ + qint64 num = 10 * 1000; + m_player->playbackEngine()->jump(-num); +} + +void NActionManager::on_speedIncreaseAction_triggered() +{ + qreal newSpeed = qMax(0.01, m_player->playbackEngine()->speed() + + m_player->settings()->value("SpeedStep").toDouble()); + m_player->playbackEngine()->setSpeed(newSpeed); + m_player->showToolTip(tr("Speed: %1").arg(m_player->playbackEngine()->speed())); +} + +void NActionManager::on_speedDecreaseAction_triggered() +{ + qreal newSpeed = qMax(0.01, m_player->playbackEngine()->speed() - + m_player->settings()->value("SpeedStep").toDouble()); + m_player->playbackEngine()->setSpeed(newSpeed); + m_player->showToolTip(tr("Speed: %1").arg(m_player->playbackEngine()->speed())); +} + +void NActionManager::on_speedResetAction_triggered() +{ + qreal newSpeed = 1.0; + m_player->playbackEngine()->setSpeed(newSpeed); + m_player->showToolTip(tr("Speed: %1").arg(m_player->playbackEngine()->speed())); +} + +void NActionManager::on_pitchIncreaseAction_triggered() +{ + qreal newPitch = qMax(0.01, m_player->playbackEngine()->pitch() + + m_player->settings()->value("PitchStep").toDouble()); + m_player->playbackEngine()->setPitch(newPitch); + m_player->showToolTip(tr("Pitch: %1").arg(m_player->playbackEngine()->pitch())); +} + +void NActionManager::on_pitchDecreaseAction_triggered() +{ + qreal newPitch = qMax(0.01, m_player->playbackEngine()->pitch() - + m_player->settings()->value("PitchStep").toDouble()); + m_player->playbackEngine()->setPitch(newPitch); + m_player->showToolTip(tr("Pitch: %1").arg(m_player->playbackEngine()->pitch())); +} + +void NActionManager::on_pitchResetAction_triggered() +{ + qreal newPitch = 1.0; + m_player->playbackEngine()->setPitch(newPitch); + m_player->showToolTip(tr("Pitch: %1").arg(m_player->playbackEngine()->pitch())); +} diff --git a/src/actionManager.h b/src/actionManager.h index c43ea20..296fd43 100644 --- a/src/actionManager.h +++ b/src/actionManager.h @@ -32,6 +32,29 @@ public: QMenu *playlistContextMenu(); QMenu *trayIconMenu(); +private slots: + void on_showCoverAction_toggled(bool checked); + void on_playingOnTopAction_toggled(bool checked); + void on_alwaysOnTopAction_toggled(bool checked); + void on_loopPlaylistAction_triggered(bool checked); + void on_scrollToItemPlaylistAction_triggered(bool checked); + void on_nextFileEnableAction_triggered(bool checked); + void on_nextFileByNameAscdAction_triggered(bool checked); + void on_nextFileByNameDescAction_triggered(bool checked); + void on_nextFileByDateAscdAction_triggered(bool checked); + void on_nextFileByDateDescAction_triggered(bool checked); + void on_revealAction_triggered(); + void on_trashSelectedAction_triggered(); + void on_tagEditorAction_triggered(); + void on_jumpForwardAction_triggered(); + void on_jumpBackwardsAction_triggered(); + void on_speedIncreaseAction_triggered(); + void on_speedDecreaseAction_triggered(); + void on_speedResetAction_triggered(); + void on_pitchIncreaseAction_triggered(); + void on_pitchDecreaseAction_triggered(); + void on_pitchResetAction_triggered(); + private: NPlayer *m_player; QMenu *m_contextMenu; diff --git a/src/common.cpp b/src/common.cpp index b625651..c9c5862 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -73,7 +73,9 @@ QString NCore::rcDir() if (!_rcDir_init) { #ifndef Q_OS_WIN QDir parentDir(QCoreApplication::applicationDirPath()); - if (parentDir.dirName() == "bin") { + // Qt4: On macOS, check for .app bundle structure (Contents/MacOS) + // Also check for standard bin directory installations + if (parentDir.dirName() == "bin" || parentDir.dirName() == "MacOS") { _rcDir = QDir::homePath() + "/.nulloy"; } else { _rcDir = QCoreApplication::applicationDirPath(); @@ -102,7 +104,8 @@ QString NCore::rcDir() #endif QDir dir(_rcDir); if (!dir.exists()) { - dir.mkdir(_rcDir); + // Qt4: Use mkpath() to create directory and any parent directories + QDir().mkpath(_rcDir); } _rcDir_init = true; diff --git a/src/interfaces/coverReaderInterface.h b/src/interfaces/coverReaderInterface.h index ee45a4e..13d2da4 100644 --- a/src/interfaces/coverReaderInterface.h +++ b/src/interfaces/coverReaderInterface.h @@ -16,6 +16,8 @@ #ifndef N_COVER_ART_READER_INTERFACE_H #define N_COVER_ART_READER_INTERFACE_H +#include +#include #include class QString; diff --git a/src/interfaces/tagReaderInterface.h b/src/interfaces/tagReaderInterface.h index a216a31..4c48cf9 100644 --- a/src/interfaces/tagReaderInterface.h +++ b/src/interfaces/tagReaderInterface.h @@ -38,7 +38,7 @@ public: virtual bool isWriteSupported() const { return false; } virtual QMap getTags() const { return QMap(); } - virtual QMap setTags(const QMap &) {} + virtual QMap setTags(const QMap &) { return QMap(); } }; Q_DECLARE_INTERFACE(NTagReaderInterface, TAGREADER_INTERFACE) diff --git a/src/main.cpp b/src/main.cpp index 34868d8..4f0e791 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,8 @@ #ifndef _N_NO_SKINS_ #include "skinFileSystem.h" -Q_IMPORT_PLUGIN(NWidgetCollection) +// Qt4 Q_IMPORT_PLUGIN must match Q_EXPORT_PLUGIN2 first parameter +Q_IMPORT_PLUGIN(widgetcollection) #endif bool logToFile = false; @@ -56,17 +57,16 @@ static void print_try() print_out("Try `" + NCore::applicationBasenameName() + " --help' for more information"); } -void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +// Qt4 uses different message handler signature (no QMessageLogContext, const char* instead of QString) +void messageHandler(QtMsgType type, const char *msg) { - Q_UNUSED(context); - print_err(msg); + QString message = QString::fromLocal8Bit(msg); + print_err(message); if (logToFile) { QString prefix; switch (type) { - case QtInfoMsg: - prefix = "Info"; - break; + // QtInfoMsg doesn't exist in Qt4, added in Qt5 case QtDebugMsg: prefix = "Debug"; break; @@ -85,7 +85,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt QTextStream stream(&logFile); stream << QString("%1 %2: %3") .arg(QTime::currentTime().toString("hh:mm:ss.zzz"), prefix, - msg.toLocal8Bit().constData()) + message.toLocal8Bit().constData()) << endl; logFile.close(); } @@ -100,8 +100,7 @@ int main(int argc, char *argv[]) QCoreApplication::addLibraryPath(QFileInfo(argv[0]).dir().path() + "/plugins/"); #endif - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // Qt4 doesn't support HiDPI attributes (AA_UseHighDpiPixmaps and AA_EnableHighDpiScaling are Qt5+) #ifdef Q_OS_MAC // https://bugreports.qt-project.org/browse/QTBUG-32789 @@ -119,7 +118,8 @@ int main(int argc, char *argv[]) instance.setOrganizationDomain("nulloy.com"); instance.setQuitOnLastWindowClosed(false); - qInstallMessageHandler(messageHandler); + // Qt4 uses qInstallMsgHandler() instead of Qt5's qInstallMessageHandler() + qInstallMsgHandler(messageHandler); QStringList argList = instance.arguments(); argList.takeFirst(); diff --git a/src/mainWindow.cpp b/src/mainWindow.cpp index 0a7ec55..c53293e 100644 --- a/src/mainWindow.cpp +++ b/src/mainWindow.cpp @@ -19,7 +19,7 @@ #include "settings.h" #ifndef _N_NO_SKINS_ -#include +#include "customUiLoader.h" #include "skinFileSystem.h" #endif @@ -35,6 +35,7 @@ #endif #endif +#include #include #include #include @@ -54,7 +55,7 @@ NMainWindow::NMainWindow(const QString &uiFile, QWidget *parent) : QDialog(paren setObjectName("mainWindow"); #ifndef _N_NO_SKINS_ - QUiLoader loader; + NCustomUiLoader loader; QFile formFile(uiFile); formFile.open(QIODevice::ReadOnly); QWidget *form = loader.load(&formFile); @@ -66,6 +67,31 @@ NMainWindow::NMainWindow(const QString &uiFile, QWidget *parent) : QDialog(paren setLayout(layout); setStyleSheet(form->styleSheet()); form->setStyleSheet(""); + + // Qt4: Explicitly enable acceptDrops and dragEnabled for custom widgets AFTER reparenting + // QUiLoader in Qt4 may not properly apply these properties from .ui file + // Must be done after widgets are added to the main window layout + QList allWidgets = findChildren(); + foreach (QWidget *widget, allWidgets) { + QString className = widget->metaObject()->className(); + if (className == "NPlaylistWidget") { + widget->setAcceptDrops(true); + // Also ensure drag-drop mode is set for QListWidget-based widgets + QAbstractItemView *itemView = qobject_cast(widget); + if (itemView) { + itemView->setDragDropMode(QAbstractItemView::DragDrop); + itemView->setDragEnabled(true); + itemView->setAcceptDrops(true); + itemView->setDropIndicatorShown(true); + // Qt4: Ensure viewport also accepts drops + if (itemView->viewport()) { + itemView->viewport()->setAcceptDrops(true); + } + } + } else if (className == "NWaveformSlider") { + widget->setAcceptDrops(true); + } + } #else Q_UNUSED(uiFile) ui.setupUi(this); @@ -450,7 +476,9 @@ void NMainWindow::wheelEvent(QWheelEvent *event) { QDialog::wheelEvent(event); - if (event->orientation() == Qt::Vertical) { + // Qt4: Only emit scrolled for global volume control if the event + // was not already handled by a child widget (like playlist scrolling) + if (event->orientation() == Qt::Vertical && !event->isAccepted()) { emit scrolled(event->delta()); } } diff --git a/src/messageBox.cpp b/src/messageBox.cpp index 578d460..427d71e 100644 --- a/src/messageBox.cpp +++ b/src/messageBox.cpp @@ -20,7 +20,7 @@ #include "messageBox.h" NMessageBox::NMessageBox(int width, QObject ¢erInTarget, QWidget *parent) - : QMessageBox(parent), m_centerInWindow{centerInTarget} + : QMessageBox(parent), m_centerInWindow(centerInTarget) { m_width = width; m_resized = false; diff --git a/src/messageBox.h b/src/messageBox.h index 7e91728..61da432 100644 --- a/src/messageBox.h +++ b/src/messageBox.h @@ -18,10 +18,10 @@ class NMessageBox : public QMessageBox { public: - NMessageBox(int width, QObject ¢erInTarget, QWidget *parent = nullptr); + NMessageBox(int width, QObject ¢erInTarget, QWidget *parent = 0); protected: - void resizeEvent(QResizeEvent *event) override; + void resizeEvent(QResizeEvent *event); private: int m_width; diff --git a/src/platform/trash.cpp b/src/platform/trash.cpp index 074fcbc..55fca41 100644 --- a/src/platform/trash.cpp +++ b/src/platform/trash.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,11 @@ QStringList NTrash::moveToTrash(QStringList files) .arg(QFileInfo(file).fileName()), QMessageBox::Yes | QMessageBox::Cancel, NULL); msgBox.setDefaultButton(QMessageBox::Cancel); - msgBox.setCheckBox(checkBox); + // Qt4 doesn't have setCheckBox(), add checkbox manually to layout + QGridLayout *layout = qobject_cast(msgBox.layout()); + if (layout) { + layout->addWidget(checkBox, layout->rowCount(), 0, 1, layout->columnCount()); + } int res = msgBox.exec(); if (res != QMessageBox::Yes) { diff --git a/src/player.cpp b/src/player.cpp index 32d1da6..e672201 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -71,7 +71,12 @@ NPlayer::NPlayer() QString styleName = m_settings->value("Style").toString(); if (!styleName.isEmpty()) { - QApplication::setStyle(styleName); + // Qt4: Normalize style names (remove parenthetical additions) + // "Macintosh (aqua)" -> "Macintosh" + styleName = styleName.split('(').first().trimmed(); + if (!styleName.isEmpty()) { + QApplication::setStyle(styleName); + } } NI18NLoader::init(); @@ -175,13 +180,12 @@ NPlayer::NPlayer() connectSignals(); m_settingsSaveTimer = new QTimer(this); - connect(m_settingsSaveTimer, &QTimer::timeout, [this]() { saveSettings(); }); + connect(m_settingsSaveTimer, SIGNAL(timeout()), this, SLOT(on_settingsSaveTimer_timeout())); m_settingsSaveTimer->start(5000); // 5 seconds m_writeDefaultPlaylistTimer = new QTimer(this); m_writeDefaultPlaylistTimer->setSingleShot(true); - connect(m_writeDefaultPlaylistTimer, &QTimer::timeout, - [this]() { writePlaylist(NCore::defaultPlaylistPath(), N::NulloyM3u); }); + connect(m_writeDefaultPlaylistTimer, SIGNAL(timeout()), this, SLOT(on_writeDefaultPlaylistTimer_timeout())); } NPlayer::~NPlayer() @@ -213,8 +217,8 @@ void NPlayer::connectSignals() connect(m_mainWindow, SIGNAL(closed()), this, SLOT(on_mainWindow_closed())); - connect(m_preferencesDialog, &NPreferencesDialog::settingsChanged, this, - &NPlayer::applySettings); + connect(m_preferencesDialog, SIGNAL(settingsChanged()), this, + SLOT(applySettings())); if (QAbstractButton *playButton = m_mainWindow->findChild("playButton")) { connect(playButton, SIGNAL(clicked()), this, SLOT(playPause())); @@ -263,45 +267,24 @@ void NPlayer::connectSignals() connect(m_playlistWidget, SIGNAL(addMoreRequested()), this, SLOT(on_playlist_addMoreRequested())); - connect(m_playlistWidget, &NPlaylistWidget::durationChanged, [this](int durationSec) { - NPlaylistWidgetItem *item = m_playlistWidget->playingItem(); - if (item) { - m_trackInfoReader->setSource(item->data(N::PathRole).toString()); - } - - m_trackInfoReader->updatePlaylistDuration(durationSec); - - m_trackInfoWidget->updatePlaylistLabels(); - - QString format = NSettings::instance()->value("WindowTitleTrackInfo").toString(); - if (!format.isEmpty()) { - QString title = m_trackInfoReader->toString(format); - m_mainWindow->setTitle(title); - } - }); - connect(m_playlistWidget, &NPlaylistWidget::itemsChanged, [this]() { - m_writeDefaultPlaylistTimer->start(100); // - }); - connect(m_playlistWidget, &NPlaylistWidget::playingItemChanged, - [this]() { savePlaybackState(); }); - connect(m_playlistWidget, &NPlaylistWidget::playlistFinished, [this]() { - if (NSettings::instance()->value("QuitWhenFinished").toBool()) { - QCoreApplication::quit(); - } - }); - - connect(m_waveformSlider, &NWaveformSlider::filesDropped, - [this](const QList &dataItems) { - m_playlistWidget->setItems(dataItems); - m_playlistWidget->playRow(0); - }); + connect(m_playlistWidget, SIGNAL(durationChanged(int)), this, + SLOT(on_playlistWidget_durationChanged(int))); + connect(m_playlistWidget, SIGNAL(itemsChanged()), this, + SLOT(on_playlistWidget_itemsChanged())); + connect(m_playlistWidget, SIGNAL(playingItemChanged()), + this, SLOT(on_playlistWidget_playingItemChanged())); + connect(m_playlistWidget, SIGNAL(playlistFinished()), this, + SLOT(on_playlistWidget_playlistFinished())); + + connect(m_waveformSlider, SIGNAL(filesDropped(QList)), + this, SLOT(on_waveformSlider_filesDropped(QList))); connect(m_waveformSlider, SIGNAL(sliderMoved(qreal)), m_playbackEngine, SLOT(setPosition(qreal))); connect(m_mainWindow, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); - connect(m_playlistWidget, &NPlaylistWidget::contextMenuRequested, this, - &NPlayer::showPlaylistContextMenu); + connect(m_playlistWidget, SIGNAL(contextMenuRequested(QPoint)), this, + SLOT(showPlaylistContextMenu(QPoint))); connect(m_systemTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_trayIcon_activated(QSystemTrayIcon::ActivationReason))); connect(m_trayClickTimer, SIGNAL(timeout()), this, SLOT(on_trayClickTimer_timeout())); @@ -406,6 +389,8 @@ void NPlayer::loadDefaultPlaylist() return; } + // Qt4: Don't auto-play on startup, only restore playlist position + // User must explicitly press play if they want to resume playback QStringList playlistRowValues = m_settings->value("PlaylistRow").toStringList(); if (!playlistRowValues.isEmpty()) { int row = playlistRowValues.at(0).toInt(); @@ -415,26 +400,22 @@ void NPlayer::loadDefaultPlaylist() return; } - if (!m_settings->value("StartPaused").toBool()) { - m_playlistWidget->playRow(row); - m_playbackEngine->setPosition(pos); - } else { // do the work that would have been done upon m_playbackEngine::mediaChanged() - NPlaylistWidgetItem *item = m_playlistWidget->itemAtRow(row); - m_playlistWidget->setPlayingItem(item); + // Set the playing item and media but don't start playback + NPlaylistWidgetItem *item = m_playlistWidget->itemAtRow(row); + m_playlistWidget->setPlayingItem(item); - QString file = item->data(N::PathRole).toString(); - int id = item->data(N::IdRole).toInt(); + QString file = item->data(N::PathRole).toString(); + int id = item->data(N::IdRole).toInt(); - m_playbackEngine->setMedia(file, id); - m_playbackEngine->setPosition(pos); + m_playbackEngine->setMedia(file, id); + m_playbackEngine->setPosition(pos); - loadCoverArt(file); + loadCoverArt(file); - m_waveformSlider->setMedia(file); - m_waveformSlider->setValue(pos); - m_waveformSlider->setPausedState(true); - m_trackInfoWidget->updateFileLabels(file); - } + m_waveformSlider->setMedia(file); + m_waveformSlider->setValue(pos); + m_waveformSlider->setPausedState(true); + m_trackInfoWidget->updateFileLabels(file); } } @@ -468,6 +449,8 @@ void NPlayer::saveSettings() m_mainWindow->saveSettings(); savePlaybackState(); m_actionManager->saveSettings(); + // Qt4: Explicitly sync settings to disk after periodic save + m_settings->sync(); } void NPlayer::savePlaybackState() @@ -843,7 +826,9 @@ bool NPlayer::revealInFileManager(const QString &file, QString *error) const cmd.replace("%P", canonicalPath); #if !defined Q_OS_WIN - res = QProcess::execute("sh", QStringList{"-c", cmd}); + QStringList args; + args << "-c" << cmd; + res = QProcess::execute("sh", args); #else res = QProcess::execute(cmd); #endif @@ -852,16 +837,16 @@ bool NPlayer::revealInFileManager(const QString &file, QString *error) const QStringList args; #if defined Q_OS_WIN cmd = "explorer.exe"; - args = QStringList{"/n", ",", "/select", ",", path.replace('/', '\\')}; + args << "/n" << "," << "/select" << "," << path.replace('/', '\\'); #elif defined Q_OS_LINUX cmd = "xdg-open"; - args = QStringList{fileInfo.canonicalPath().replace("'", "'\\''")}; + args << fileInfo.canonicalPath().replace("'", "'\\''"); #elif defined Q_OS_MAC cmd = "open"; - args = QStringList{"-R", path.replace("'", "'\\''")}; + args << "-R" << path.replace("'", "'\\''"); #endif res = QProcess::execute(cmd, args); - cmd += " " + args.join(' '); + cmd += " " + args.join(QString(" ")); } #ifndef Q_OS_WIN @@ -876,3 +861,54 @@ bool NPlayer::revealInFileManager(const QString &file, QString *error) const return true; } + +void NPlayer::on_settingsSaveTimer_timeout() +{ + saveSettings(); +} + +void NPlayer::on_writeDefaultPlaylistTimer_timeout() +{ + writePlaylist(NCore::defaultPlaylistPath(), N::NulloyM3u); +} + +void NPlayer::on_playlistWidget_durationChanged(int durationSec) +{ + NPlaylistWidgetItem *item = m_playlistWidget->playingItem(); + if (item) { + m_trackInfoReader->setSource(item->data(N::PathRole).toString()); + } + + m_trackInfoReader->updatePlaylistDuration(durationSec); + + m_trackInfoWidget->updatePlaylistLabels(); + + QString format = NSettings::instance()->value("WindowTitleTrackInfo").toString(); + if (!format.isEmpty()) { + QString title = m_trackInfoReader->toString(format); + m_mainWindow->setTitle(title); + } +} + +void NPlayer::on_playlistWidget_itemsChanged() +{ + m_writeDefaultPlaylistTimer->start(100); +} + +void NPlayer::on_playlistWidget_playingItemChanged() +{ + savePlaybackState(); +} + +void NPlayer::on_playlistWidget_playlistFinished() +{ + if (NSettings::instance()->value("QuitWhenFinished").toBool()) { + QCoreApplication::quit(); + } +} + +void NPlayer::on_waveformSlider_filesDropped(const QList &dataItems) +{ + m_playlistWidget->setItems(dataItems); + m_playlistWidget->playRow(0); +} diff --git a/src/player.h b/src/player.h index dad9890..c0835c9 100644 --- a/src/player.h +++ b/src/player.h @@ -28,6 +28,7 @@ class NPlaylistWidget; class NWaveformSlider; class NCoverWidget; class NCoverReaderInterface; +struct NPlaylistDataItem; class NVolumeSlider; class NPreferencesDialog; class NAboutDialog; @@ -101,6 +102,14 @@ private slots: void on_trayClickTimer_timeout(); void trayIconCountClicks(int clicks); + void on_settingsSaveTimer_timeout(); + void on_writeDefaultPlaylistTimer_timeout(); + void on_playlistWidget_durationChanged(int durationSec); + void on_playlistWidget_itemsChanged(); + void on_playlistWidget_playingItemChanged(); + void on_playlistWidget_playlistFinished(); + void on_waveformSlider_filesDropped(const QList &dataItems); + public slots: void quit(); void playPause(); diff --git a/src/plugins/pluginGstreamer/containerGstreamer.cpp b/src/plugins/pluginGstreamer/containerGstreamer.cpp index 2340267..1e8d3b0 100644 --- a/src/plugins/pluginGstreamer/containerGstreamer.cpp +++ b/src/plugins/pluginGstreamer/containerGstreamer.cpp @@ -43,3 +43,5 @@ QList NContainerGstreamer::plugins() const { return m_plugins; } + +Q_EXPORT_PLUGIN2(containerGstreamer, NContainerGstreamer) diff --git a/src/plugins/pluginGstreamer/containerGstreamer.h b/src/plugins/pluginGstreamer/containerGstreamer.h index 93b9f2c..cf41956 100644 --- a/src/plugins/pluginGstreamer/containerGstreamer.h +++ b/src/plugins/pluginGstreamer/containerGstreamer.h @@ -22,7 +22,6 @@ class NContainerGstreamer : public QObject, public NPluginContainer { Q_OBJECT Q_INTERFACES(NPluginContainer) - Q_PLUGIN_METADATA(IID "com.nulloy.NContainerGstreamer") private: QList m_plugins; diff --git a/src/plugins/pluginGstreamer/playbackEngineGstreamer.cpp b/src/plugins/pluginGstreamer/playbackEngineGstreamer.cpp index af1c932..ec57a57 100644 --- a/src/plugins/pluginGstreamer/playbackEngineGstreamer.cpp +++ b/src/plugins/pluginGstreamer/playbackEngineGstreamer.cpp @@ -121,18 +121,11 @@ void NPlaybackEngineGStreamer::init() m_emitStateTimer = new QTimer(this); m_emitStateTimer->setSingleShot(true); m_emitStateTimer->setInterval(STATE_CHANGE_DEBOUNCE_MSEC); - connect(m_emitStateTimer, &QTimer::timeout, - [this]() { emit stateChanged(fromGstState(m_gstState)); }); + connect(m_emitStateTimer, SIGNAL(timeout()), this, SLOT(on_emitStateTimer_timeout())); m_gstBusPopTimer = new QTimer(this); m_gstBusPopTimer->setInterval(GST_BUS_POP_MSEC); - connect(m_gstBusPopTimer, &QTimer::timeout, [this]() { - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_playbin)); - GstMessage *msg; - while ((msg = gst_bus_pop(bus)) != NULL) { - processGstMessage(msg); - } - }); + connect(m_gstBusPopTimer, SIGNAL(timeout()), this, SLOT(on_gstBusPopTimer_timeout())); m_init = true; } @@ -376,7 +369,7 @@ void NPlaybackEngineGStreamer::processGstMessage(GstMessage *msg) gchar *detail = gst_missing_plugin_message_get_installer_detail(msg); if (detail) { QStringList fields = QString::fromUtf8(detail).split('|').mid(3); - str += QString::fromUtf8(detail).split('|').mid(3).join("
"); + str += fields.join("
"); g_free(detail); } else { str += tr("Unknown plugin"); @@ -486,3 +479,17 @@ bool NPlaybackEngineGStreamer::_nextMediaRequestBlocked() { return m_nextMediaRequestBlock; } + +void NPlaybackEngineGStreamer::on_emitStateTimer_timeout() +{ + emit stateChanged(fromGstState(m_gstState)); +} + +void NPlaybackEngineGStreamer::on_gstBusPopTimer_timeout() +{ + GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_playbin)); + GstMessage *msg; + while ((msg = gst_bus_pop(bus)) != NULL) { + processGstMessage(msg); + } +} diff --git a/src/plugins/pluginGstreamer/playbackEngineGstreamer.h b/src/plugins/pluginGstreamer/playbackEngineGstreamer.h index 35be620..05b8fff 100644 --- a/src/plugins/pluginGstreamer/playbackEngineGstreamer.h +++ b/src/plugins/pluginGstreamer/playbackEngineGstreamer.h @@ -57,6 +57,10 @@ private: void processGstMessage(GstMessage *msg); void fail(); +private slots: + void on_emitStateTimer_timeout(); + void on_gstBusPopTimer_timeout(); + public: NPlaybackEngineGStreamer(QObject *parent = NULL) : NPlaybackEngineInterface(parent) {} ~NPlaybackEngineGStreamer(); diff --git a/src/plugins/pluginTaglib/containerTaglib.cpp b/src/plugins/pluginTaglib/containerTaglib.cpp index f6ce5d9..7dba764 100644 --- a/src/plugins/pluginTaglib/containerTaglib.cpp +++ b/src/plugins/pluginTaglib/containerTaglib.cpp @@ -33,3 +33,5 @@ QList NContainerTaglib::plugins() const { return m_plugins; } + +Q_EXPORT_PLUGIN2(containerTaglib, NContainerTaglib) diff --git a/src/plugins/pluginTaglib/containerTaglib.h b/src/plugins/pluginTaglib/containerTaglib.h index a0b4999..c3a2d3a 100644 --- a/src/plugins/pluginTaglib/containerTaglib.h +++ b/src/plugins/pluginTaglib/containerTaglib.h @@ -22,7 +22,6 @@ class NContainerTaglib : public QObject, public NPluginContainer { Q_OBJECT Q_INTERFACES(NPluginContainer) - Q_PLUGIN_METADATA(IID "com.nulloy.NContainerTaglib") private: QList m_plugins; diff --git a/src/plugins/pluginTaglib/coverReaderTaglib.cpp b/src/plugins/pluginTaglib/coverReaderTaglib.cpp index 398c968..37667fd 100644 --- a/src/plugins/pluginTaglib/coverReaderTaglib.cpp +++ b/src/plugins/pluginTaglib/coverReaderTaglib.cpp @@ -79,7 +79,7 @@ QList NCoverReaderTaglib::fromApe(TagLib::APE::Tag *tag) const QList images; const TagLib::APE::ItemListMap &map = tag->itemListMap(); - for (auto iter = map.begin(); iter != map.end(); ++iter) { + for (TagLib::APE::ItemListMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter) { TagLib::String key = iter->first; if (!key.startsWith("COVER ART")) { continue; @@ -105,8 +105,8 @@ QList NCoverReaderTaglib::fromAsf(TagLib::ASF::Tag *tag) const const TagLib::ASF::AttributeList &list = map[str]; - for (auto attribute : list) { - TagLib::ASF::Picture pic = attribute.toPicture(); + for (TagLib::ASF::AttributeList::ConstIterator it = list.begin(); it != list.end(); ++it) { + TagLib::ASF::Picture pic = it->toPicture(); if (pic.isValid()) { images << fromTagBytes(pic.picture()); } @@ -120,8 +120,8 @@ QList NCoverReaderTaglib::fromFlac(TagLib::FLAC::File *file) const QList images; const TagLib::List &list = file->pictureList(); - for (TagLib::FLAC::Picture *pic : list) { - images << fromTagBytes(pic->data()); + for (TagLib::List::ConstIterator it = list.begin(); it != list.end(); ++it) { + images << fromTagBytes((*it)->data()); } return images; } @@ -134,8 +134,8 @@ QList NCoverReaderTaglib::fromId3(TagLib::ID3v2::Tag *tag) const return images; } - for (auto *frame : list) { - auto pictureFrame = static_cast(frame); + for (TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it) { + TagLib::ID3v2::AttachedPictureFrame *pictureFrame = static_cast(*it); images << fromTagBytes(pictureFrame->picture()); } return images; @@ -150,8 +150,8 @@ QList NCoverReaderTaglib::fromMp4(TagLib::MP4::Tag *tag) const } TagLib::MP4::CoverArtList coverList = tag->itemMap()[str].toCoverArtList(); - for (auto coverArt : coverList) { - images << fromTagBytes(coverArt.data()); + for (TagLib::MP4::CoverArtList::ConstIterator it = coverList.begin(); it != coverList.end(); ++it) { + images << fromTagBytes(it->data()); } return images; @@ -160,7 +160,7 @@ QList NCoverReaderTaglib::fromMp4(TagLib::MP4::Tag *tag) const QList NCoverReaderTaglib::fromVorbis(TagLib::Tag *tag) const { QList images; - if (auto *comment = dynamic_cast(tag)) { + if (TagLib::Ogg::XiphComment *comment = dynamic_cast(tag)) { TagLib::String str = "COVERART"; if (!comment->contains(str)) { @@ -193,29 +193,29 @@ QList NCoverReaderTaglib::getImages() const TagLib::File *tagFile = NTaglib::_tagRef->file(); - if (auto *file = dynamic_cast(tagFile)) { + if (TagLib::APE::File *file = dynamic_cast(tagFile)) { if (file->APETag()) { images = fromApe(file->APETag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::ASF::File *file = dynamic_cast(tagFile)) { if (file->tag()) { images = fromAsf(file->tag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::FLAC::File *file = dynamic_cast(tagFile)) { images = fromFlac(file); if (images.isEmpty() && file->ID3v2Tag()) { images = fromId3(file->ID3v2Tag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::MP4::File *file = dynamic_cast(tagFile)) { if (file->tag()) { images = fromMp4(file->tag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::MPC::File *file = dynamic_cast(tagFile)) { if (file->APETag()) { images = fromApe(file->APETag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::MPEG::File *file = dynamic_cast(tagFile)) { if (file->ID3v2Tag()) { images = fromId3(file->ID3v2Tag()); } @@ -223,11 +223,11 @@ QList NCoverReaderTaglib::getImages() const if (images.isEmpty() && file->APETag()) { images = fromApe(file->APETag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::Ogg::Vorbis::File *file = dynamic_cast(tagFile)) { if (file->tag()) { images = fromVorbis(file->tag()); } - } else if (auto *file = dynamic_cast(tagFile)) { + } else if (TagLib::WavPack::File *file = dynamic_cast(tagFile)) { if (file->APETag()) { images = fromApe(file->APETag()); } diff --git a/src/plugins/pluginTaglib/tagReaderTaglib.cpp b/src/plugins/pluginTaglib/tagReaderTaglib.cpp index c54f711..26af1f1 100644 --- a/src/plugins/pluginTaglib/tagReaderTaglib.cpp +++ b/src/plugins/pluginTaglib/tagReaderTaglib.cpp @@ -35,7 +35,7 @@ QString NTaglib::_filePath; NTagReaderTaglib::NTagReaderTaglib(QObject *parent) : NTagReaderInterface(parent) { m_isValid = false; - m_codec = nullptr; + m_codec = 0; m_utf8Codec = QTextCodec::codecForName("UTF-8"); } @@ -141,19 +141,19 @@ QString NTagReaderTaglib::getTag(QChar ch) const } case 'b': { // bit depth TagLib::AudioProperties *ap = NTaglib::_tagRef->audioProperties(); - if (auto *prop = dynamic_cast(ap)) { + if (TagLib::APE::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::FLAC::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::MP4::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::RIFF::AIFF::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::RIFF::WAV::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::TrueAudio::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); - } else if (auto *prop = dynamic_cast(ap)) { + } else if (TagLib::WavPack::Properties *prop = dynamic_cast(ap)) { return QString::number(prop->bitsPerSample()); } else { return ""; @@ -264,11 +264,11 @@ QMap NTagReaderTaglib::TMapToQMap(const TagLib::Map &tmap) const { QMap qmap; - for (auto iter = tmap.begin(); iter != tmap.end(); ++iter) { + for (TagLib::Map::ConstIterator iter = tmap.begin(); iter != tmap.end(); ++iter) { QStringList values; TagLib::StringList tlist = iter->second; - for (auto iter = tlist.begin(); iter != tlist.end(); ++iter) { - values << toUnicode((*iter)); + for (TagLib::StringList::ConstIterator iter2 = tlist.begin(); iter2 != tlist.end(); ++iter2) { + values << toUnicode((*iter2)); } qmap[TStringToQString(iter->first)] = values; } diff --git a/src/preferencesDialog.cpp b/src/preferencesDialog.cpp index 658a5a4..11de850 100644 --- a/src/preferencesDialog.cpp +++ b/src/preferencesDialog.cpp @@ -96,8 +96,8 @@ NPreferencesDialog::NPreferencesDialog(NPlayer *player, QWidget *parent) : QDial #ifdef _N_NO_UPDATE_CHECK_ ui.autoCheckUpdatesContainer->hide(); #else - connect(&NUpdateChecker::instance(), &NUpdateChecker::versionChanged, this, - &NPreferencesDialog::setVersionLabel); + connect(&NUpdateChecker::instance(), SIGNAL(versionChanged(QString)), this, + SLOT(setVersionLabel(QString))); #endif #if defined Q_OS_WIN || defined Q_OS_MAC @@ -111,8 +111,8 @@ NPreferencesDialog::NPreferencesDialog(NPlayer *player, QWidget *parent) : QDial ui.quitOnCloseContainer->hide(); #endif - QRegularExpression re("Container$"); - for (QWidget *widget : ui.generalTab->findChildren(re)) { + QRegExp re("Container$"); + foreach (QWidget *widget, ui.generalTab->findChildren(re)) { if (widget->objectName() == "fileFiltersContainer") { continue; } @@ -158,7 +158,7 @@ NPreferencesDialog::NPreferencesDialog(NPlayer *player, QWidget *parent) : QDial ui.styleRestartLabel->setVisible(false); connect(ui.styleComboBox, SIGNAL(activated(int)), ui.styleRestartLabel, SLOT(show())); - ui.waveformTrackInfoTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + ui.waveformTrackInfoTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); int i = 0; foreach (int mib, QTextCodec::availableMibs()) { @@ -398,7 +398,7 @@ void NPreferencesDialog::on_languageComboBox_activated(int index) QString newText = NI18NLoader::translate(locale.language(), "PreferencesDialog", "Switching languages requires restart"); ui.languageRestartLabel->setText( - ui.languageRestartLabel->text().replace(QRegExp("(.*) .*"), "\\1 " + newText)); + ui.languageRestartLabel->text().replace(QRegExp("(.*) .*"), "\\\\1 " + newText)); } QString NPreferencesDialog::selectedContainer(N::PluginType type) @@ -566,7 +566,9 @@ void NPreferencesDialog::loadSettings() // shortcuts >> QList actionList; - for (NAction *action : m_player->findChildren()) { + QList allActions = m_player->findChildren(); + for (int i = 0; i < allActions.size(); ++i) { + NAction *action = allActions.at(i); if (action->objectName().isEmpty() || !action->isCustomizable()) { continue; } @@ -678,6 +680,9 @@ void NPreferencesDialog::saveSettings() ui.shortcutEditorWidget->applyShortcuts(); // << shortcuts + // Qt4: Explicitly sync settings to disk after all changes + NSettings::instance()->sync(); + emit settingsChanged(); // systray check >> diff --git a/src/scriptEngine.cpp b/src/scriptEngine.cpp index ace9224..b08bb44 100644 --- a/src/scriptEngine.cpp +++ b/src/scriptEngine.cpp @@ -203,7 +203,7 @@ NScriptEngine::NScriptEngine(NPlayer *player) : QScriptEngine(player) setDefaultPrototype(qMetaTypeId(), newQObject(&widgetPrototype)); setDefaultPrototype(qMetaTypeId(), newQObject(&layoutPrototype)); setDefaultPrototype(qMetaTypeId(), newQObject(&splitterPrototype)); - qScriptRegisterSequenceMetaType>(this); + qScriptRegisterSequenceMetaType >(this); qScriptRegisterMetaType(this, enumToScriptValue, enumFromScriptValue); QScriptValue N = newQMetaObject(&N::staticMetaObject); diff --git a/src/settings.cpp b/src/settings.cpp index 82c0f43..f7f0abf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -18,10 +18,11 @@ #include #include #include +#include #include #include -#include #include +#include #include #include "action.h" @@ -37,7 +38,8 @@ NSettings::NSettings(QObject *parent) Q_ASSERT_X(!m_instance, "NSettings", "NSettings instance already exists."); m_instance = this; - setIniCodec("UTF-8"); + // Qt4: setIniCodec() requires QTextCodec* parameter + setIniCodec(QTextCodec::codecForName("UTF-8")); QString version = value("SettingsVersion").toString(); if (version.isEmpty() || version < MIN_VERSION) { @@ -81,13 +83,9 @@ NSettings::NSettings(QObject *parent) initValue("PitchStep", 0.01); */ - { - QStringList fullScreenKeys; - foreach (QKeySequence seq, QKeySequence::keyBindings(QKeySequence::FullScreen)) { - fullScreenKeys << seq.toString(); - } - initValue("Shortcuts/FullScreenAction", QStringList() << fullScreenKeys); - } + // Qt4 doesn't have QKeySequence::keyBindings or QKeySequence::FullScreen + // Use common fullscreen shortcuts manually + initValue("Shortcuts/FullScreenAction", QStringList() << "F11"); initValue("PlaylistTrackInfo", "%F{ (%d)}"); initValue("WindowTitleTrackInfo", @@ -110,7 +108,7 @@ NSettings::NSettings(QObject *parent) initValue("DisplayLogDialog", true); initValue("DisplayTagEditorConfirmDialog", true); initValue("DisplayMoveToTrashConfirmDialog", true); - initValue("LastDirectory", QStandardPaths::standardLocations(QStandardPaths::MusicLocation)); + initValue("LastDirectory", QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); initValue("ScrollToItem", true); initValue("LoopPlaylist", false); initValue("LoadNext", false); @@ -178,7 +176,11 @@ void NSettings::setValue(const QString &key, const QVariant &value) void NSettings::initValue(const QString &key, const QVariant &defaultValue) { QVariant val = value(key, defaultValue); - val.convert(defaultValue.type()); + // Qt4: convert() modifies in-place and returns bool success + if (!val.convert(defaultValue.type())) { + // Conversion failed, use default value + val = defaultValue; + } setValue(key, val); } diff --git a/src/shortcutEditorWidget.cpp b/src/shortcutEditorWidget.cpp index e341b51..a26f6d0 100644 --- a/src/shortcutEditorWidget.cpp +++ b/src/shortcutEditorWidget.cpp @@ -68,10 +68,10 @@ void NShortcutEditorWidget::init(const QList &actionList) resizeColumnToContents(Name); resizeColumnToContents(Description); - horizontalHeader()->setSectionResizeMode(Name, QHeaderView::Fixed); - horizontalHeader()->setSectionResizeMode(Description, QHeaderView::Fixed); - horizontalHeader()->setSectionResizeMode(Shortcut, QHeaderView::Stretch); - horizontalHeader()->setSectionResizeMode(GlobalShortcut, QHeaderView::Stretch); + horizontalHeader()->setResizeMode(Name, QHeaderView::Fixed); + horizontalHeader()->setResizeMode(Description, QHeaderView::Fixed); + horizontalHeader()->setResizeMode(Shortcut, QHeaderView::Stretch); + horizontalHeader()->setResizeMode(GlobalShortcut, QHeaderView::Stretch); horizontalHeader()->setStretchLastSection(true); } diff --git a/src/src.pri b/src/src.pri index 6ca941d..fd474f8 100644 --- a/src/src.pri +++ b/src/src.pri @@ -1,4 +1,4 @@ -QT += script gui svg core-private +QT += script gui svg INCLUDEPATH += $$SRC_DIR $$SRC_DIR/interfaces @@ -35,6 +35,8 @@ unix:!mac:PKGCONFIG += x11 !no-skins { include($$SRC_DIR/skins/skins.pri) QT += uitools + # Qt4 on macOS requires explicit QtUiTools library linking + mac:LIBS += -lQtUiTools INCLUDEPATH += $$SRC_DIR/widgetCollection LIBS += -L$$SRC_DIR/widgetCollection -lwidget_collection PRE_TARGETDEPS += $$SRC_DIR/widgetCollection/libwidget_collection.a @@ -57,7 +59,9 @@ unix:!mac:PKGCONFIG += x11 FORMS += $$SRC_DIR/skins/native/form.ui } -no-update-check:DEFINES += _N_NO_UPDATE_CHECK_ +# Qt4: Always disable update checking (MacPorts handles updates) +DEFINES += _N_NO_UPDATE_CHECK_ +# no-update-check:DEFINES += _N_NO_UPDATE_CHECK_ include(version.pri) DEFINES += _N_VERSION_=\""\\\"$${N_VERSION}\\\""\" diff --git a/src/tagEditorDialog.cpp b/src/tagEditorDialog.cpp index 1914d0e..bace3a7 100644 --- a/src/tagEditorDialog.cpp +++ b/src/tagEditorDialog.cpp @@ -29,6 +29,7 @@ #include #include #include +#include NTagEditorDialog::NTagEditorDialog(const QString &file, QWidget *parent) : QDialog(parent) { @@ -77,23 +78,15 @@ NTagEditorDialog::NTagEditorDialog(const QString &file, QWidget *parent) : QDial } ++i; } - connect(ui.encodingResetButton, &QPushButton::clicked, [=] { - ui.encodingComboBox->setCurrentIndex(m_encodingUtf8Index); - on_encodingComboBox_activated(-1); - }); - connect(ui.editAsUtf8Button, &QPushButton::clicked, [=] { - ui.encodingComboBox->setCurrentIndex(m_encodingUtf8Index); - m_encodingPreviousIndex = m_encodingUtf8Index; - m_hasChanges = true; - setReadOnlyMode(false); - }); + connect(ui.encodingResetButton, SIGNAL(clicked()), this, SLOT(onEncodingResetClicked())); + connect(ui.editAsUtf8Button, SIGNAL(clicked()), this, SLOT(onEditAsUtf8Clicked())); on_encodingComboBox_activated(-1); setWindowTitle("\"" + QFileInfo(file).fileName() + "\" — " + tr("Tag Editor")); m_coverReader->setSource(m_file); QList images = m_coverReader->getImages(); - for (QImage image : images) { + foreach (QImage image, images) { QLabel *label = new QLabel; label->setFixedSize(100, 100); label->setScaledContents(true); @@ -107,11 +100,7 @@ NTagEditorDialog::NTagEditorDialog(const QString &file, QWidget *parent) : QDial ui.artworkListWidget->setMinimumHeight(111); ui.buttonBox->button(QDialogButtonBox::Reset)->setText(tr("Revert")); - connect(ui.buttonBox->button(QDialogButtonBox::Reset), &QPushButton::clicked, [=] { - ui.encodingComboBox->setCurrentIndex(m_encodingSettingsIndex); - readTags(); - setReadOnlyMode(ui.encodingComboBox->currentIndex() != m_encodingUtf8Index); - }); + connect(ui.buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(onRevertClicked())); exec(); } @@ -161,7 +150,7 @@ void NTagEditorDialog::readTags() } // create raw widgets for standard tags: - QRegularExpression widgetNameRegex("Tag"); + QRegExp widgetNameRegex("Tag"); m_tagReader->setSource(m_file); QMap tags = m_tagReader->getTags(); m_tagReader->setSource(""); // release the file @@ -182,11 +171,7 @@ void NTagEditorDialog::readTags() QLineEdit *rawTagLineEdit = new QLineEdit(value); rawTagsFormLayout->addRow(label, rawTagLineEdit); - connect(rawTagLineEdit, &QLineEdit::textEdited, [=](const QString &newValue) { - m_hasChanges = true; - ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); - ui.buttonBox->button(QDialogButtonBox::Reset)->setEnabled(true); - }); + connect(rawTagLineEdit, SIGNAL(textEdited(QString)), this, SLOT(onTagTextChanged())); if (label.isEmpty()) { // connect widgets only for the first tag value continue; @@ -196,36 +181,24 @@ void NTagEditorDialog::readTags() if (QLineEdit *standardTagLineEdit = ui.generalTab->findChild( widgetNamePrefix + "LineEdit")) { standardTagLineEdit->setText(values.first()); - QMetaObject::Connection connection = - connect(standardTagLineEdit, &QLineEdit::textEdited, - [=](const QString &newValue) { - rawTagLineEdit->setText(newValue); - m_hasChanges = true; - ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); - ui.buttonBox->button(QDialogButtonBox::Reset)->setEnabled(true); - }); - connect(rawTagLineEdit, &QObject::destroyed, - [=] { QObject::disconnect(connection); }); - connect(rawTagLineEdit, &QLineEdit::textEdited, - [=](const QString &newValue) { standardTagLineEdit->setText(newValue); }); + + // Store bidirectional widget associations using properties + standardTagLineEdit->setProperty("rawTagWidget", qVariantFromValue((QObject*)rawTagLineEdit)); + rawTagLineEdit->setProperty("standardTagWidget", qVariantFromValue((QObject*)standardTagLineEdit)); + rawTagLineEdit->setProperty("isLineEdit", true); + + connect(standardTagLineEdit, SIGNAL(textEdited(QString)), this, SLOT(onTagTextChanged())); } else if (QPlainTextEdit *standardTagPlainTextEdit = ui.generalTab->findChild(widgetNamePrefix + "PlainTextEdit")) { standardTagPlainTextEdit->setPlainText(values.first()); - QMetaObject::Connection connection = - connect(standardTagPlainTextEdit, &QPlainTextEdit::textChanged, [=] { - rawTagLineEdit->setText(standardTagPlainTextEdit->toPlainText()); - m_hasChanges = true; - ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); - ui.buttonBox->button(QDialogButtonBox::Reset)->setEnabled(true); - }); - connect(rawTagLineEdit, &QObject::destroyed, - [=] { QObject::disconnect(connection); }); - connect(rawTagLineEdit, &QLineEdit::textEdited, [=](const QString &newValue) { - QTextCursor cursor = standardTagPlainTextEdit->textCursor(); - standardTagPlainTextEdit->setPlainText(newValue); - standardTagPlainTextEdit->setTextCursor(cursor); - }); + + // Store bidirectional widget associations using properties + standardTagPlainTextEdit->setProperty("rawTagWidget", qVariantFromValue((QObject*)rawTagLineEdit)); + rawTagLineEdit->setProperty("standardTagWidget", qVariantFromValue((QObject*)standardTagPlainTextEdit)); + rawTagLineEdit->setProperty("isLineEdit", false); + + connect(standardTagPlainTextEdit, SIGNAL(textChanged()), this, SLOT(onTagTextChanged())); } else { QMessageBox::critical(NULL, tr("Match error"), tr("No widget for tag: %1").arg(enumKey), QMessageBox::Close); @@ -271,7 +244,8 @@ bool NTagEditorDialog::writeTags() valueList.clear(); } QLabel *label = qobject_cast(item->widget()); - tagName = label->text().chopped(1); + // Qt4 doesn't have QString::chopped(), use left() instead + tagName = label->text().left(label->text().length() - 1); } QString value = qobject_cast( rawTagsFormLayout->itemAt(i, QFormLayout::FieldRole)->widget()) @@ -295,7 +269,8 @@ bool NTagEditorDialog::writeTags() msgBox.exec(); } else { QMessageBox msgBox(QMessageBox::Warning, tr("Save Fail"), - tr("Saving aborted. Failed tags: %1").arg(unsaved.keys().join(", ")), + // Qt4 QList doesn't have join(), convert to QStringList first + tr("Saving aborted. Failed tags: %1").arg(QStringList(unsaved.keys()).join(", ")), QMessageBox::Close, this); msgBox.exec(); } @@ -307,6 +282,80 @@ bool NTagEditorDialog::writeTags() NTagEditorDialog::~NTagEditorDialog() {} +void NTagEditorDialog::onEncodingResetClicked() +{ + ui.encodingComboBox->setCurrentIndex(m_encodingUtf8Index); + on_encodingComboBox_activated(-1); +} + +void NTagEditorDialog::onEditAsUtf8Clicked() +{ + ui.encodingComboBox->setCurrentIndex(m_encodingUtf8Index); + m_encodingPreviousIndex = m_encodingUtf8Index; + m_hasChanges = true; + setReadOnlyMode(false); +} + +void NTagEditorDialog::onRevertClicked() +{ + ui.encodingComboBox->setCurrentIndex(m_encodingSettingsIndex); + readTags(); + setReadOnlyMode(ui.encodingComboBox->currentIndex() != m_encodingUtf8Index); +} + +void NTagEditorDialog::onTagTextChanged() +{ + m_hasChanges = true; + ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true); + ui.buttonBox->button(QDialogButtonBox::Reset)->setEnabled(true); + + QObject *senderWidget = sender(); + if (!senderWidget) { + return; + } + + // Check if this widget has an associated widget to sync with + QVariant rawTagVariant = senderWidget->property("rawTagWidget"); + QVariant standardTagVariant = senderWidget->property("standardTagWidget"); + + if (rawTagVariant.isValid()) { + // This is a standard tag widget, update the raw tag widget + QLineEdit *rawTagLineEdit = qobject_cast( + qvariant_cast(rawTagVariant)); + if (rawTagLineEdit) { + QLineEdit *standardLineEdit = qobject_cast(senderWidget); + QPlainTextEdit *standardPlainTextEdit = qobject_cast(senderWidget); + + if (standardLineEdit) { + rawTagLineEdit->setText(standardLineEdit->text()); + } else if (standardPlainTextEdit) { + rawTagLineEdit->setText(standardPlainTextEdit->toPlainText()); + } + } + } else if (standardTagVariant.isValid()) { + // This is a raw tag widget, update the standard tag widget + QLineEdit *rawTagLineEdit = qobject_cast(senderWidget); + if (rawTagLineEdit) { + QObject *standardWidget = qvariant_cast(standardTagVariant); + bool isLineEdit = senderWidget->property("isLineEdit").toBool(); + + if (isLineEdit) { + QLineEdit *standardLineEdit = qobject_cast(standardWidget); + if (standardLineEdit) { + standardLineEdit->setText(rawTagLineEdit->text()); + } + } else { + QPlainTextEdit *standardPlainTextEdit = qobject_cast(standardWidget); + if (standardPlainTextEdit) { + QTextCursor cursor = standardPlainTextEdit->textCursor(); + standardPlainTextEdit->setPlainText(rawTagLineEdit->text()); + standardPlainTextEdit->setTextCursor(cursor); + } + } + } + } +} + void NTagEditorDialog::onSaveClicked() { if (NSettings::instance()->value("DisplayTagEditorConfirmDialog").toBool()) { @@ -316,7 +365,11 @@ void NTagEditorDialog::onSaveClicked() tr("Do you want to save your changes?"), QMessageBox::Save | QMessageBox::Cancel, this); msgBox.setDefaultButton(QMessageBox::Save); - msgBox.setCheckBox(checkBox); + // Qt4 doesn't have setCheckBox(), add checkbox manually to layout + QGridLayout *layout = qobject_cast(msgBox.layout()); + if (layout) { + layout->addWidget(checkBox, layout->rowCount(), 0, 1, layout->columnCount()); + } int res = msgBox.exec(); if (res != QMessageBox::Save) { diff --git a/src/tagEditorDialog.h b/src/tagEditorDialog.h index 08889d9..eeae7df 100644 --- a/src/tagEditorDialog.h +++ b/src/tagEditorDialog.h @@ -41,6 +41,7 @@ private: bool m_hasChanges; void readTags(); bool writeTags(); + void onTagTextChanged(); public: NTagEditorDialog(const QString &file, QWidget *parent = 0); @@ -50,6 +51,9 @@ private slots: void on_encodingComboBox_activated(int index); void onSaveClicked(); void setReadOnlyMode(bool readOnly); + void onEncodingResetClicked(); + void onEditAsUtf8Clicked(); + void onRevertClicked(); }; #endif diff --git a/src/trackInfoReader.cpp b/src/trackInfoReader.cpp index 167f842..a648176 100644 --- a/src/trackInfoReader.cpp +++ b/src/trackInfoReader.cpp @@ -23,10 +23,11 @@ QString NTrackInfoReader::formatTime(int durationSec) int minutes = (durationSec - seconds) / 60; int hours = minutes / 60; minutes = minutes % 60; + // Qt4 doesn't have QString::asprintf() (added in Qt 5.5), use QString::sprintf() instead if (hours > 0) { - return QString::asprintf("%d:%02d:%02d", hours, minutes, seconds); + return QString().sprintf("%d:%02d:%02d", hours, minutes, seconds); } else { - return QString::asprintf("%d:%02d", minutes, seconds); + return QString().sprintf("%d:%02d", minutes, seconds); } } diff --git a/src/updateChecker.cpp b/src/updateChecker.cpp index 652b5fa..106e23b 100644 --- a/src/updateChecker.cpp +++ b/src/updateChecker.cpp @@ -33,7 +33,7 @@ NUpdateChecker &NUpdateChecker::instance() NUpdateChecker::NUpdateChecker() { m_networkManager = new QNetworkAccessManager(this); - connect(m_networkManager, &QNetworkAccessManager::finished, this, &NUpdateChecker::on_finished); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_finished(QNetworkReply*))); } QString NUpdateChecker::version() const diff --git a/src/waveformPeaks.cpp b/src/waveformPeaks.cpp index 4f0627d..031493e 100644 --- a/src/waveformPeaks.cpp +++ b/src/waveformPeaks.cpp @@ -32,7 +32,7 @@ void NWaveformPeaks::reset() m_counter = 0; m_completed = false; - m_vector = QVector>(MAX_RES, qMakePair(0.0, 0.0)); + m_vector = QVector >(MAX_RES, qMakePair(0.0, 0.0)); } int NWaveformPeaks::size() const diff --git a/src/waveformPeaks.h b/src/waveformPeaks.h index e7fd7bc..19afcde 100644 --- a/src/waveformPeaks.h +++ b/src/waveformPeaks.h @@ -23,7 +23,7 @@ class NWaveformPeaks { private: - QVector> m_vector; + QVector > m_vector; bool m_completed; int m_index; int m_factor; diff --git a/src/widgetCollection/playlistWidget.cpp b/src/widgetCollection/playlistWidget.cpp index 401aa14..c65940c 100644 --- a/src/widgetCollection/playlistWidget.cpp +++ b/src/widgetCollection/playlistWidget.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -45,9 +46,7 @@ NPlaylistWidget::NPlaylistWidget(QWidget *parent) : QListWidget(parent) Q_ASSERT(m_playbackEngine); // triggered bu user input (double click or enter, depending on platform): - connect(this, &QListWidget::itemActivated, [this](QListWidgetItem *item) { - playItem(reinterpret_cast(item)); - }); + connect(this, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(on_itemActivated(QListWidgetItem*))); connect(m_playbackEngine, SIGNAL(mediaFinished(const QString &, int)), this, SLOT(on_playbackEngine_mediaFinished(const QString &, int))); connect(m_playbackEngine, SIGNAL(mediaFailed(const QString &, int)), this, @@ -74,10 +73,7 @@ NPlaylistWidget::NPlaylistWidget(QWidget *parent) : QListWidget(parent) m_processVisibleItemsTimer = new QTimer(this); m_processVisibleItemsTimer->setSingleShot(true); - connect(m_processVisibleItemsTimer, &QTimer::timeout, [this]() { - processVisibleItems(); - calculateDuration(); - }); + connect(m_processVisibleItemsTimer, SIGNAL(timeout()), this, SLOT(on_processVisibleItemsTimer_timeout())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(startProcessVisibleItemsTimer())); } @@ -125,7 +121,7 @@ void NPlaylistWidget::processVisibleItems() QStringList NPlaylistWidget::selectedFiles() const { QStringList files; - for (QListWidgetItem *item : selectedItems()) { + foreach (QListWidgetItem *item, selectedItems()) { files << item->data(N::PathRole).toString(); } return files; @@ -137,6 +133,33 @@ void NPlaylistWidget::wheelEvent(QWheelEvent *event) event->accept(); } +void NPlaylistWidget::keyPressEvent(QKeyEvent *event) +{ + // Qt4: Handle Delete and Backspace keys for removing selected items + // On macOS, Cmd+Backspace is the standard delete shortcut + bool isDeleteKey = (event->key() == Qt::Key_Delete || + event->key() == Qt::Key_Backspace); + +#ifdef Q_OS_MAC + // macOS: Cmd+Backspace + bool isDeleteShortcut = (event->key() == Qt::Key_Backspace && + event->modifiers() & Qt::MetaModifier); +#else + // Linux/Windows: Ctrl+Backspace + bool isDeleteShortcut = (event->key() == Qt::Key_Backspace && + event->modifiers() & Qt::ControlModifier); +#endif + + if ((isDeleteKey || isDeleteShortcut) && selectedItems().count() > 0) { + removeSelected(); + event->accept(); + return; + } + + // For all other keys, use default QListWidget behavior + QListWidget::keyPressEvent(event); +} + void NPlaylistWidget::contextMenuEvent(QContextMenuEvent *event) { if (selectedItems().size() != 0 && itemAt(event->pos())) { @@ -156,7 +179,7 @@ void NPlaylistWidget::removeFiles(const QStringList &files) } std::reverse(rowsToRemove.begin(), rowsToRemove.end()); - for (int row : rowsToRemove) { + foreach (int row, rowsToRemove) { delete takeItem(row); } @@ -742,6 +765,12 @@ void NPlaylistWidget::dragEnterEvent(QDragEnterEvent *event) } QListWidget::dragEnterEvent(event); + + // Qt4: Explicitly accept external file drops (from Finder/file manager) + // QListWidget::dragEnterEvent only accepts internal drags (item reordering) + if (event->mimeData() && event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } } void NPlaylistWidget::dragMoveEvent(QDragMoveEvent *event) @@ -751,6 +780,11 @@ void NPlaylistWidget::dragMoveEvent(QDragMoveEvent *event) } QListWidget::dragMoveEvent(event); + + // Qt4: Explicitly accept external file drops during drag move + if (event->mimeData() && event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } } void NPlaylistWidget::dragLeaveEvent(QDragLeaveEvent *event) @@ -819,3 +853,14 @@ void NPlaylistWidget::setFileDropRadius(int radius) m_fileDropRadius = radius; } // << STYLESHEET PROPERTIES + +void NPlaylistWidget::on_itemActivated(QListWidgetItem *item) +{ + playItem(reinterpret_cast(item)); +} + +void NPlaylistWidget::on_processVisibleItemsTimer_timeout() +{ + processVisibleItems(); + calculateDuration(); +} diff --git a/src/widgetCollection/playlistWidget.h b/src/widgetCollection/playlistWidget.h index f78340a..0979aff 100644 --- a/src/widgetCollection/playlistWidget.h +++ b/src/widgetCollection/playlistWidget.h @@ -22,7 +22,7 @@ #include "global.h" -class NPlaylistDataItem; +struct NPlaylistDataItem; class NPlaylistWidgetItem; class NTrackInfoReader; class NPlaybackEngineInterface; @@ -61,6 +61,7 @@ private: protected: void wheelEvent(QWheelEvent *event); + void keyPressEvent(QKeyEvent *event); protected slots: void rowsInserted(const QModelIndex &parent, int start, int end); @@ -70,6 +71,8 @@ private slots: void on_playbackEngine_mediaChanged(const QString &file, int id); void on_playbackEngine_prepareNextMediaRequested(); + void on_itemActivated(QListWidgetItem *item); + void on_processVisibleItemsTimer_timeout(); void on_playbackEngine_mediaFinished(const QString &file, int id); void on_playbackEngine_mediaFailed(const QString &file, int id); @@ -125,13 +128,13 @@ public: DragStartInside, DragStartOutside }; - Q_ENUM(DragStart) + Q_ENUMS(DragStart) enum DropEnd { DropEndInside, DropEndOutside }; - Q_ENUM(DropEnd) + Q_ENUMS(DropEnd) private: DragStart m_dragStart; DropEnd m_dropEnd; diff --git a/src/widgetCollection/playlistWidgetItem.cpp b/src/widgetCollection/playlistWidgetItem.cpp index 6768019..7821bbc 100644 --- a/src/widgetCollection/playlistWidgetItem.cpp +++ b/src/widgetCollection/playlistWidgetItem.cpp @@ -124,7 +124,7 @@ void NPlaylistWidgetItemDelegate::paint(QPainter *painter, const QStyleOptionVie const QModelIndex &index) const { QStyleOptionViewItem opt = option; - const NPlaylistWidget *playlistWidget = qobject_cast(opt.widget); + const NPlaylistWidget *playlistWidget = qobject_cast(parent()); if (index.data(N::FailedRole).toBool()) { // FailedRole has higher priority than PlayingRole QColor color = playlistWidget->failedTextColor(); diff --git a/src/widgetCollection/slider.h b/src/widgetCollection/slider.h index fa15f9b..dcd2dc9 100644 --- a/src/widgetCollection/slider.h +++ b/src/widgetCollection/slider.h @@ -27,9 +27,9 @@ public: qreal valueAtPos(int pos); protected: - virtual void mousePressEvent(QMouseEvent *event) override; - virtual void mouseMoveEvent(QMouseEvent *event) override; - virtual void wheelEvent(QWheelEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void wheelEvent(QWheelEvent *event); private slots: void setValue(int){}; diff --git a/src/widgetCollection/volumeSlider.h b/src/widgetCollection/volumeSlider.h index b51062a..84ae9e2 100644 --- a/src/widgetCollection/volumeSlider.h +++ b/src/widgetCollection/volumeSlider.h @@ -26,9 +26,9 @@ public: NVolumeSlider(QWidget *parent); private: - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void wheelEvent(QWheelEvent *e) override; + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *e); QString toolTipText(int value) const; private slots: diff --git a/src/widgetCollection/waveformSlider.cpp b/src/widgetCollection/waveformSlider.cpp index d784ec6..02f6cf2 100644 --- a/src/widgetCollection/waveformSlider.cpp +++ b/src/widgetCollection/waveformSlider.cpp @@ -119,9 +119,8 @@ void NWaveformSlider::checkForUpdate() if (m_needsUpdate) { QPainter painter; - qreal dpr = devicePixelRatioF(); + qreal dpr = 1.0; // Qt4 doesn't have 1.0 QImage image(width() * dpr, height() * dpr, QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(dpr); QImage waveImage; waveImage = m_backgroundImage = m_progressPlayingImage = m_progressPausedImage = m_remainingPlayingImage = m_remainingPausedImage = image; @@ -200,7 +199,7 @@ void NWaveformSlider::paintEvent(QPaintEvent *) if (m_hasMedia) { qreal x = (qreal)value() / maximum() * width(); - qreal dpr = devicePixelRatioF(); + qreal dpr = 1.0; QTransform transform; transform.scale(dpr, dpr); diff --git a/src/widgetCollection/waveformSlider.h b/src/widgetCollection/waveformSlider.h index 7473fcb..01ba016 100644 --- a/src/widgetCollection/waveformSlider.h +++ b/src/widgetCollection/waveformSlider.h @@ -20,7 +20,7 @@ #include #include -class NPlaylistDataItem; +struct NPlaylistDataItem; class NWaveformBuilderInterface; class NWaveformSlider : public QAbstractSlider diff --git a/src/widgetCollection/widgetCollection.cpp b/src/widgetCollection/widgetCollection.cpp index 4bfb613..6643810 100644 --- a/src/widgetCollection/widgetCollection.cpp +++ b/src/widgetCollection/widgetCollection.cpp @@ -27,10 +27,10 @@ // clang-format off #define N_WIDGET_PLUGIN(CLASS_NAME) \ -class CLASS_NAME##Plugin : public QObject, public NWidgetPlugin \ +class CLASS_NAME##Plugin : public NWidgetPlugin \ { \ public: \ - CLASS_NAME##Plugin(QObject *parent = 0) : QObject(parent), NWidgetPlugin(#CLASS_NAME) {} \ + CLASS_NAME##Plugin(QObject *parent = 0) : NWidgetPlugin(#CLASS_NAME) { Q_UNUSED(parent); } \ virtual QWidget* createWidget(QWidget *parent) { return new CLASS_NAME(parent); } \ virtual bool isContainer() const { return false; } \ }; \ @@ -79,7 +79,7 @@ void NWidgetPlugin::initialize(QDesignerFormEditorInterface *core) m_initialized = true; } -NWidgetCollection::NWidgetCollection(QObject *parent) : QObject(parent) +NWidgetCollection::NWidgetCollection(QObject *parent) : QObject(parent), QDesignerCustomWidgetCollectionInterface() { m_plugins.push_back(new NWaveformSliderPlugin(this)); m_plugins.push_back(new QSizeGripPlugin(this)); @@ -89,3 +89,5 @@ NWidgetCollection::NWidgetCollection(QObject *parent) : QObject(parent) m_plugins.push_back(new NLabelPlugin(this)); m_plugins.push_back(new NCoverWidgetPlugin(this)); } + +Q_EXPORT_PLUGIN2(widgetcollection, NWidgetCollection) diff --git a/src/widgetCollection/widgetCollection.h b/src/widgetCollection/widgetCollection.h index 7dd84e4..f7c562b 100644 --- a/src/widgetCollection/widgetCollection.h +++ b/src/widgetCollection/widgetCollection.h @@ -25,9 +25,11 @@ #include #endif -class NWidgetPlugin : public QDesignerCustomWidgetInterface +class NWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface { - Q_INTERFACES(QDesignerCustomWidgetInterface) + Q_OBJECT + // Q_INTERFACES not needed for Qt4 static plugins using Q_EXPORT_PLUGIN2 + // Only the collection class (NWidgetCollection) needs Q_INTERFACES private: bool m_initialized; @@ -42,6 +44,8 @@ public: QString name() const { return m_className; } void initialize(QDesignerFormEditorInterface *core); bool isInitialized() const { return m_initialized; } + virtual QWidget *createWidget(QWidget *parent) = 0; + virtual bool isContainer() const = 0; virtual QIcon icon() const { return QIcon(); } virtual QString whatsThis() const { return QString(); } virtual QString toolTip() const { return QString(); } @@ -53,8 +57,7 @@ public: class NWidgetCollection : public QObject, public QDesignerCustomWidgetCollectionInterface { Q_OBJECT - Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) - Q_PLUGIN_METADATA(IID "com.nulloy.NWidgetCollection") + // Q_INTERFACES not needed for Qt4 static plugins using Q_EXPORT_PLUGIN2 public: NWidgetCollection(QObject *parent = 0); diff --git a/src/widgetCollection/widgetCollection.pro b/src/widgetCollection/widgetCollection.pro index 2e45ae6..4229fb9 100644 --- a/src/widgetCollection/widgetCollection.pro +++ b/src/widgetCollection/widgetCollection.pro @@ -2,7 +2,9 @@ TEMPLATE = lib TARGET = widget_collection DESTDIR = $$PWD -QT += designer gui +# Qt4 doesn't have separate designer module, Qt5+ does +greaterThan(QT_MAJOR_VERSION, 4): QT += designer +QT += gui CONFIG += plugin static include(widgetCollection.pri) diff --git a/tests/testPlaylistWidget.cpp b/tests/testPlaylistWidget.cpp index f767eba..6562762 100644 --- a/tests/testPlaylistWidget.cpp +++ b/tests/testPlaylistWidget.cpp @@ -61,8 +61,8 @@ private slots: void cleanup() { delete m_playlistWidget; - m_playlistWidget = nullptr; - m_playbackEngine = nullptr; + m_playlistWidget = 0; + m_playbackEngine = 0; } void testPlaylistRemoval() diff --git a/src/customUiLoader.h b/src/customUiLoader.h new file mode 100644 index 0000000..7c22024 --- /dev/null +++ b/src/customUiLoader.h @@ -0,0 +1,83 @@ +/******************************************************************** +** Nulloy Music Player, http://nulloy.com +** Copyright (C) 2010-2024 Sergey Vlasov +** +** This program can be distributed under the terms of the GNU +** General Public License version 3.0 as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the +** following information to ensure the GNU General Public License +** version 3.0 requirements will be met: +** +** http://www.gnu.org/licenses/gpl-3.0.html +** +*********************************************************************/ + +#ifndef N_CUSTOM_UI_LOADER_H +#define N_CUSTOM_UI_LOADER_H + +#include + +#ifndef _N_NO_SKINS_ + +#include "widgetCollection/coverWidget.h" +#include "widgetCollection/label.h" +#include "widgetCollection/playlistWidget.h" +#include "widgetCollection/volumeSlider.h" +#include "widgetCollection/waveformSlider.h" + +// Custom QUiLoader for Qt4 static plugin widgets +// Qt4's QUiLoader doesn't automatically discover static plugins, +// so we need to manually instantiate our custom widgets +class NCustomUiLoader : public QUiLoader +{ +public: + NCustomUiLoader(QObject *parent = 0) : QUiLoader(parent) {} + + // Override availableWidgets to include our custom widgets + // This tells QUiLoader that these widgets exist + QStringList availableWidgets() const + { + QStringList widgets = QUiLoader::availableWidgets(); + widgets << "NLabel"; + widgets << "NWaveformSlider"; + widgets << "NVolumeSlider"; + widgets << "NPlaylistWidget"; + widgets << "NCoverWidget"; + return widgets; + } + +protected: + QWidget *createWidget(const QString &className, QWidget *parent = 0, + const QString &name = QString()) + { + if (className == "NLabel") { + NLabel *widget = new NLabel(parent); + widget->setObjectName(name); + return widget; + } else if (className == "NWaveformSlider") { + NWaveformSlider *widget = new NWaveformSlider(parent); + widget->setObjectName(name); + return widget; + } else if (className == "NVolumeSlider") { + NVolumeSlider *widget = new NVolumeSlider(parent); + widget->setObjectName(name); + return widget; + } else if (className == "NPlaylistWidget") { + NPlaylistWidget *widget = new NPlaylistWidget(parent); + widget->setObjectName(name); + return widget; + } else if (className == "NCoverWidget") { + NCoverWidget *widget = new NCoverWidget(parent); + widget->setObjectName(name); + return widget; + } + + // For all other widgets, use default QUiLoader behavior + return QUiLoader::createWidget(className, parent, name); + } +}; + +#endif // _N_NO_SKINS_ + +#endif // N_CUSTOM_UI_LOADER_H