From 118283b748359c3268f47e382762c90cd5c412ac Mon Sep 17 00:00:00 2001
From: Javier <dev.git@javispedro.com>
Date: Sun, 19 Sep 2021 22:22:23 +0200
Subject: replace Phonon with QtMultimedia

---
 README.md     |   6 ++--
 mainwindow.cc | 102 +++++++++++++++++++++++++++++++++-------------------------
 mainwindow.h  |  17 +++++-----
 mainwindow.ui |  62 +++++++++++++++++++++++++----------
 scribiu.pro   |   3 +-
 5 files changed, 116 insertions(+), 74 deletions(-)

diff --git a/README.md b/README.md
index e8b0fac..2ddee0e 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,8 @@ It also allows you to export individual pages as PNG files or voice memos as AAC
 
 # Requirements
 
-Scribiu requires Qt 5, including the core, gui, widgets, and svg modules.
-It also requires phonon, libudev, openobex (>=1.7), libusb (>=1.0) and QuaZip (1.0).
+Scribiu requires Qt 5, including the core, gui, widgets, svg and multimedia modules.
+It also requires libudev, openobex (>=1.7), libusb (>=1.0) and QuaZip (1.0).
 Most of these should be packaged by your distribution.
 
 For example, on Ubuntu, these correspond with packages:
@@ -19,7 +19,7 @@ For example, on Ubuntu, these correspond with packages:
 `
 qtbase5-dev
 libqt5svg5-dev
-libphonon4qt5-dev
+qtmultimedia5-dev
 libudev-dev
 libopenobex2-dev
 libusb-1.0-0-dev
diff --git a/mainwindow.cc b/mainwindow.cc
index d8a935c..b66423a 100644
--- a/mainwindow.cc
+++ b/mainwindow.cc
@@ -25,13 +25,14 @@
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
 
+#define PAPER_REPLAY_SLIDER_SCALE 100LL /* in msec */
+
 MainWindow::MainWindow(QWidget *parent) :
     QMainWindow(parent),
     ui(new Ui::MainWindow),
     _notebooks(new NotebookModel(this)),
     _manager(new SmartpenManager(this)),
-    _media(new Phonon::MediaObject(this)),
-    _mediaOutput(new Phonon::AudioOutput(this)),
+    _player(new QMediaPlayer(this)),
     _replay(new PaperReplay(this)),
     _replayModel(new PaperReplayModel(_replay, this)),
     _statusLabel(new QLabel)
@@ -42,14 +43,15 @@ MainWindow::MainWindow(QWidget *parent) :
 	ui->notebookTree->header()->setSectionResizeMode(1, QHeaderView::Fixed);
 	ui->notebookTree->header()->setSectionResizeMode(2, QHeaderView::Fixed);
 	ui->notebookTree->expandAll();
+	ui->replaySlider->setSingleStep(5000 / PAPER_REPLAY_SLIDER_SCALE);
+	ui->replaySlider->setPageStep(30000 / PAPER_REPLAY_SLIDER_SCALE);
 	ui->paperReplayView->setModel(_replayModel);
 	ui->paperReplayView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
 	ui->paperReplayView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
-	Phonon::createPath(_media, _mediaOutput);
-	_media->setTickInterval(500);
-	ui->replaySlider->setMediaObject(_media);
 	ui->pauseButton->setVisible(false);
 	ui->statusBar->addWidget(_statusLabel, 1);
+	_player->setAudioRole(QAudio::VideoRole);
+
 	connect(_notebooks, SIGNAL(rowsInserted(QModelIndex,int,int)),
 	        this, SLOT(handleNotebookRowsInserted(QModelIndex,int,int)));
 	connect(_manager, SIGNAL(pensBeingSynchronizedChanged()),
@@ -58,12 +60,14 @@ MainWindow::MainWindow(QWidget *parent) :
 	        this, SLOT(handlePenSyncComplete(QString)));
 	connect(_manager, SIGNAL(syncFailed(QString)),
 	        this, SLOT(handlePenSyncFailed(QString)));
-	connect(_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
-	        this, SLOT(handleMediaStateChange(Phonon::State)));
-	connect(_media, SIGNAL(totalTimeChanged(qint64)),
-	        this, SLOT(handleMediaTotalTimeChanged(qint64)));
-	connect(_media, SIGNAL(tick(qint64)),
-	        this, SLOT(handleMediaTick(qint64)));
+	connect(_player, SIGNAL(stateChanged(QMediaPlayer::State)),
+	        this, SLOT(handlePlayerStateChanged(QMediaPlayer::State)));
+	connect(_player, SIGNAL(durationChanged(qint64)),
+	        this, SLOT(handlePlayerDurationChanged(qint64)));
+	connect(_player, SIGNAL(positionChanged(qint64)),
+	        this, SLOT(handlePlayerPositionChanged(qint64)));
+	connect(_player, SIGNAL(seekableChanged(bool)),
+	        this, SLOT(handlePlayerSeekableChanged(bool)));
 
 	QSettings settings;
 	settings.beginGroup("mainwindow");
@@ -168,8 +172,8 @@ void MainWindow::exportCurrentPageAsInkML(const QString &file)
 
 void MainWindow::exportCurrentPaperReplayAsAac(const QString &file)
 {
-	QString src = _media->currentSource().fileName();
-	if (src.isEmpty()) {
+	QString src = currentPlayerMediaPath();
+	if (src.isNull()) {
 		QMessageBox::warning(this, tr("Export audio"),
 		                     tr("No audio file is selected"));
 		return;
@@ -229,75 +233,80 @@ void MainWindow::handlePaperReplayRequested(const QString &file, qint64 time)
 
 	QString filePath = finfo.canonicalFilePath();
 
-	if (_media->currentSource().fileName() != filePath) {
+	if (currentPlayerMediaPath() != filePath) {
 		qDebug() << "requesting media " << filePath;
-		_media->setCurrentSource(QUrl::fromLocalFile(filePath));
+		_player->setMedia(QUrl::fromLocalFile(filePath));
 	}
 
-	qDebug() << "requesting media seek to" << time << "/" << _media->totalTime();
+	qDebug() << "requesting media seek to" << time << "/" << _player->duration();
 
-	switch (_media->state()) {
-	case Phonon::PlayingState:
-	case Phonon::BufferingState:
-	case Phonon::PausedState:
+	if (_player->isSeekable()) {
+		// Media is loaded and ready to go
 		_pendingSeek = 0;
-		_media->seek(time);
-		break;
-	default:
+		_player->setPosition(time);
+	} else {
+		// Otherwise delay the seek until after media starts playing
 		_pendingSeek = time;
-		break;
 	}
 
-	_media->play();
+	_player->play();
 }
 
 void MainWindow::handlePaperReplayPlay()
 {
-	_media->play();
+	_player->play();
 }
 
 void MainWindow::handlePaperReplayPause()
 {
-	_media->pause();
+	_player->pause();
 }
 
-void MainWindow::handleMediaStateChange(Phonon::State state)
+void MainWindow::handlePaperReplaySliderChanged(int value)
+{
+	_player->setPosition(value * PAPER_REPLAY_SLIDER_SCALE);
+}
+
+void MainWindow::handlePlayerStateChanged(QMediaPlayer::State state)
 {
 	switch (state) {
-	case Phonon::PlayingState:
+	case QMediaPlayer::PlayingState:
 		ui->playButton->setVisible(false);
 		ui->pauseButton->setVisible(true);
-		if (_pendingSeek) {
-			qDebug() << "requesting (pending) media seek to" << _pendingSeek << "/" << _media->totalTime();
-			_media->seek(_pendingSeek);
-			_pendingSeek = 0;
-		}
-		ui->mediaPosLabel->setText(formatDuration(_media->currentTime()));
-		ui->mediaLenLabel->setText("/ " + formatDuration(_media->totalTime()));
 		break;
-	case Phonon::PausedState:
+	case QMediaPlayer::PausedState:
 		ui->playButton->setVisible(true);
 		ui->pauseButton->setVisible(false);
-		ui->mediaPosLabel->setText(formatDuration(_media->currentTime()));
-		ui->mediaLenLabel->setText("/ " + formatDuration(_media->totalTime()));
 		break;
 	default:
 		ui->playButton->setVisible(true);
 		ui->pauseButton->setVisible(false);
-		ui->mediaPosLabel->setText(QString());
-		ui->mediaLenLabel->setText(QString());
 		break;
 	}
 }
 
-void MainWindow::handleMediaTotalTimeChanged(qint64 time)
+void MainWindow::handlePlayerDurationChanged(qint64 time)
 {
 	ui->mediaLenLabel->setText("/ " + formatDuration(time));
+	ui->replaySlider->setMaximum(time / PAPER_REPLAY_SLIDER_SCALE);
 }
 
-void MainWindow::handleMediaTick(qint64 time)
+void MainWindow::handlePlayerPositionChanged(qint64 time)
 {
 	ui->mediaPosLabel->setText(formatDuration(time));
+	if (!ui->replaySlider->isSliderDown()) {
+		QSignalBlocker blocker(ui->replaySlider);
+		ui->replaySlider->setValue(time / PAPER_REPLAY_SLIDER_SCALE);
+	}
+}
+
+void MainWindow::handlePlayerSeekableChanged(bool seekable)
+{
+	if (seekable && _pendingSeek) {
+		qDebug() << "requesting (pending) media seek to" << _pendingSeek << "/" << _player->duration();
+		_player->setPosition(_pendingSeek);
+		_pendingSeek = 0;
+	}
 }
 
 void MainWindow::handlePensBeingSynchronizedChanged()
@@ -431,7 +440,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
 	settings.endGroup();
 }
 
-QString MainWindow::formatDuration(qint64 time)
+QString MainWindow::formatDuration(qint64 time) const
 {
 	int secs = time / 1000;
 	int mins = secs / 60;
@@ -446,3 +455,8 @@ QString MainWindow::formatDuration(qint64 time)
 		return QString("%2:%3").arg(mins).arg(secs, 2, 10, fill);
 	}
 }
+
+QString MainWindow::currentPlayerMediaPath() const
+{
+	return _player->media().request().url().toLocalFile();
+}
diff --git a/mainwindow.h b/mainwindow.h
index 2f5575c..03479a2 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -21,8 +21,7 @@
 
 #include <QtWidgets/QMainWindow>
 #include <QtWidgets/QLabel>
-#include <phonon/MediaObject>
-#include <phonon/AudioOutput>
+#include <QtMultimedia/QMediaPlayer>
 #include "notebookmodel.h"
 #include "paperreplaymodel.h"
 #include "smartpenmanager.h"
@@ -57,9 +56,11 @@ private slots:
 	void handlePaperReplayRequested(const QString &file, qint64 time);
 	void handlePaperReplayPlay();
 	void handlePaperReplayPause();
-	void handleMediaStateChange(Phonon::State state);
-	void handleMediaTotalTimeChanged(qint64 time);
-	void handleMediaTick(qint64 time);
+	void handlePaperReplaySliderChanged(int value);
+	void handlePlayerStateChanged(QMediaPlayer::State state);
+	void handlePlayerDurationChanged(qint64 time);
+	void handlePlayerPositionChanged(qint64 time);
+	void handlePlayerSeekableChanged(bool seekable);
 	void handlePensBeingSynchronizedChanged();
 	void handlePenSyncComplete(const QString &penName);
 	void handlePenSyncFailed(const QString &penName);
@@ -70,15 +71,15 @@ protected:
 	void closeEvent(QCloseEvent *event);
 
 private:
-	QString formatDuration(qint64 time);
+	QString formatDuration(qint64 time) const;
+	QString currentPlayerMediaPath() const;
 
 private:
 	Ui::MainWindow *ui;
 	NotebookModel *_notebooks;
 	SmartpenManager *_manager;
 
-	Phonon::MediaObject *_media;
-	Phonon::AudioOutput *_mediaOutput;
+	QMediaPlayer *_player;
 	qint64 _pendingSeek;
 
 	QString _curPenName;
diff --git a/mainwindow.ui b/mainwindow.ui
index a56ffba..03ae438 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -259,10 +259,27 @@
            </widget>
           </item>
           <item>
-           <widget class="Phonon::SeekSlider" name="replaySlider"/>
+           <widget class="QSlider" name="replaySlider">
+            <property name="maximum">
+             <number>0</number>
+            </property>
+            <property name="tracking">
+             <bool>false</bool>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="tickInterval">
+             <number>1</number>
+            </property>
+           </widget>
           </item>
           <item>
-           <widget class="QLabel" name="mediaPosLabel"/>
+           <widget class="QLabel" name="mediaPosLabel">
+            <property name="alignment">
+             <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+            </property>
+           </widget>
           </item>
           <item>
            <widget class="QLabel" name="mediaLenLabel">
@@ -345,12 +362,6 @@
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <customwidgets>
-  <customwidget>
-   <class>Phonon::SeekSlider</class>
-   <extends>QWidget</extends>
-   <header location="global">phonon/seekslider.h</header>
-   <container>1</container>
-  </customwidget>
   <customwidget>
    <class>NotebookView</class>
    <extends>QGraphicsView</extends>
@@ -406,7 +417,7 @@
    <slot>handlePaperReplayPlay()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>357</x>
+     <x>331</x>
      <y>356</y>
     </hint>
     <hint type="destinationlabel">
@@ -422,7 +433,7 @@
    <slot>handlePaperReplayPause()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>391</x>
+     <x>365</x>
      <y>356</y>
     </hint>
     <hint type="destinationlabel">
@@ -502,8 +513,8 @@
    <slot>prevPage()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>347</x>
-     <y>46</y>
+     <x>331</x>
+     <y>61</y>
     </hint>
     <hint type="destinationlabel">
      <x>441</x>
@@ -518,8 +529,8 @@
    <slot>nextPage()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>436</x>
-     <y>38</y>
+     <x>421</x>
+     <y>61</y>
     </hint>
     <hint type="destinationlabel">
      <x>473</x>
@@ -566,8 +577,8 @@
    <slot>handlePaperReplaySelected(QModelIndex)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>367</x>
-     <y>117</y>
+     <x>402</x>
+     <y>95</y>
     </hint>
     <hint type="destinationlabel">
      <x>778</x>
@@ -586,7 +597,7 @@
      <y>116</y>
     </hint>
     <hint type="destinationlabel">
-     <x>613</x>
+     <x>715</x>
      <y>62</y>
     </hint>
    </hints>
@@ -607,6 +618,22 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>replaySlider</sender>
+   <signal>valueChanged(int)</signal>
+   <receiver>MainWindow</receiver>
+   <slot>handlePaperReplaySliderChanged(int)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>416</x>
+     <y>339</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>681</x>
+     <y>300</y>
+    </hint>
+   </hints>
+  </connection>
  </connections>
  <slots>
   <slot>handleNotebookSelected(QModelIndex)</slot>
@@ -616,6 +643,7 @@
   <slot>handlePaperReplayPlay()</slot>
   <slot>handlePaperReplayPause()</slot>
   <slot>handlePaperReplaySelected(QModelIndex)</slot>
+  <slot>handlePaperReplaySliderChanged(int)</slot>
   <slot>handleExport()</slot>
   <slot>handleAbout()</slot>
  </slots>
diff --git a/scribiu.pro b/scribiu.pro
index d25f2fc..1672062 100644
--- a/scribiu.pro
+++ b/scribiu.pro
@@ -2,8 +2,7 @@ TARGET = scribiu
 VERSION = 1.4
 TEMPLATE = app
 
-QT       += core gui widgets svg
-QT       += phonon4qt5
+QT       += core gui widgets svg multimedia
 
 CONFIG += c++11
 
-- 
cgit v1.2.3