summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Whiting <jpwhiting@kde.org>2014-11-08 04:33:23 (GMT)
committerJeremy Whiting <jpwhiting@kde.org>2015-02-23 19:24:44 (GMT)
commit61554c833ed0c009cf977de7d9b0984221cc9e17 (patch)
treea042c2811728179eade4356284c97719b7e2641a
parent5c85b83a8f45503a5f08f24814da45adc60d11a4 (diff)
Reenabled text to speech using QtSpeech as an optional dependency.
If QtSpeech (dev branch) is built and installed this builds and works very well. REVIEW:122553
-rw-r--r--CMakeLists.txt17
-rw-r--r--conf/okular.kcfg2
-rw-r--r--part.cpp31
-rw-r--r--ui/pageview.cpp117
-rw-r--r--ui/pageview.h2
-rw-r--r--ui/tts.cpp107
-rw-r--r--ui/tts.h11
7 files changed, 126 insertions, 161 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b9bc1f4..d8aa16b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,13 @@ include(ECMAddTests)
find_package(Qt5 CONFIG REQUIRED COMPONENTS Core DBus Test Widgets PrintSupport Svg Qml Quick)
+find_package(Qt5 OPTIONAL_COMPONENTS TextToSpeech)
+if (NOT Qt5TextToSpeech_FOUND)
+ message(STATUS "Qt5TextToSpeech not found, speech features will be disabled")
+else()
+ add_definitions(-DHAVE_SPEECH)
+endif()
+
find_package(KF5 REQUIRED COMPONENTS
Activities
Archive
@@ -253,10 +260,14 @@ set(okularpart_SRCS
ui/toc.cpp
ui/tocmodel.cpp
ui/toolaction.cpp
-# ui/tts.cpp
ui/videowidget.cpp
)
+if (Qt5TextToSpeech_FOUND)
+ set(okularpart_SRCS ${okularpart_SRCS}
+ ui/tts.cpp)
+endif()
+
ki18n_wrap_ui(okularpart_SRCS
conf/dlgaccessibilitybase.ui
conf/dlgeditorbase.ui
@@ -268,7 +279,6 @@ ki18n_wrap_ui(okularpart_SRCS
kconfig_add_kcfg_files(okularpart_SRCS conf/settings.kcfgc )
-message("KF5: Enable ui/tts.cpp again")
#qt5_add_dbus_interfaces(okularpart_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.KSpeech.xml)
add_library(okularpart MODULE ${okularpart_SRCS})
@@ -276,6 +286,9 @@ generate_export_header(okularpart BASE_NAME okularpart)
target_link_libraries(okularpart okularcore Qt5::Svg KF5::Parts ${MATH_LIB} Phonon::phonon4qt5 KF5::Solid)
+if (Qt5TextToSpeech_FOUND)
+ target_link_libraries(okularpart Qt5::TextToSpeech)
+endif()
install(TARGETS okularpart DESTINATION ${PLUGIN_INSTALL_DIR})
diff --git a/conf/okular.kcfg b/conf/okular.kcfg
index 55f5cdc..cd1d733 100644
--- a/conf/okular.kcfg
+++ b/conf/okular.kcfg
@@ -95,7 +95,7 @@
<choice name="Path" />
</choices>
</entry>
- <entry key="UseKTTSD" type="Bool" />
+ <entry key="UseTTS" type="Bool" />
<entry key="WatchFile" type="Bool" >
<default>true</default>
</entry>
diff --git a/part.cpp b/part.cpp
index 395b0e4..aa1decb 100644
--- a/part.cpp
+++ b/part.cpp
@@ -304,7 +304,7 @@ m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentW
}
}
Okular::Settings::instance( configFileName );
-
+
numberOfParts++;
if (numberOfParts == 1) {
QDBusConnection::sessionBus().registerObject("/okular", this, QDBusConnection::ExportScriptableSlots);
@@ -506,10 +506,11 @@ m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentW
// keep us informed when the user changes settings
connect( Okular::Settings::self(), SIGNAL(configChanged()), this, SLOT(slotNewConfig()) );
- // [SPEECH] check for KTTSD presence and usability
- const KService::Ptr kttsd = KService::serviceByDesktopName("kttsd");
- Okular::Settings::setUseKTTSD( kttsd );
+#ifdef HAVE_SPEECH
+ // [SPEECH] check for TTS presence and usability
+ Okular::Settings::setUseTTS( true );
Okular::Settings::self()->save();
+#endif
rebuildBookmarkMenu( false );
@@ -1708,7 +1709,7 @@ void Part::slotFileDirty( const QString& path )
void Part::slotDoFileDirty()
{
bool tocReloadPrepared = false;
-
+
// do the following the first time the file is reloaded
if ( m_viewportDirty.pageNumber == -1 )
{
@@ -1725,7 +1726,7 @@ void Part::slotDoFileDirty()
// store if presentation view was open
m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
-
+
// preserves the toc state after reload
m_toc->prepareForReload();
tocReloadPrepared = true;
@@ -1743,13 +1744,13 @@ void Part::slotDoFileDirty()
{
m_viewportDirty.pageNumber = -1;
- if ( tocReloadPrepared )
+ if ( tocReloadPrepared )
{
m_toc->rollbackReload();
}
return;
}
-
+
if ( tocReloadPrepared )
m_toc->finishReload();
@@ -1783,7 +1784,7 @@ void Part::slotDoFileDirty()
}
else
{
- // start watching the file again (since we dropped it on close)
+ // start watching the file again (since we dropped it on close)
addFileToWatcher( m_watcher, localFilePath() );
m_dirtyHandler->start( 750 );
}
@@ -1796,14 +1797,14 @@ void Part::updateViewActions()
if ( opened )
{
m_gotoPage->setEnabled( m_document->pages() > 1 );
-
+
// Check if you are at the beginning or not
if (m_document->currentPage() != 0)
{
m_beginningOfDocument->setEnabled( true );
m_prevPage->setEnabled( true );
}
- else
+ else
{
if (m_pageView->verticalScrollBar()->value() != 0)
{
@@ -1818,7 +1819,7 @@ void Part::updateViewActions()
// The document is at the first page, you can go to a page before
m_prevPage->setEnabled( false );
}
-
+
if (m_document->pages() == m_document->currentPage() + 1 )
{
// If you are at the end, disable go to next page
@@ -1828,13 +1829,13 @@ void Part::updateViewActions()
// If you are the end of the page of the last document, you can't go to the last page
m_endOfDocument->setEnabled( false );
}
- else
+ else
{
// Otherwise you can move to the endif
m_endOfDocument->setEnabled( true );
}
}
- else
+ else
{
// If you are not at the end, enable go to next page
m_nextPage->setEnabled( true );
@@ -2936,7 +2937,7 @@ void Part::rebuildBookmarkMenu( bool unplugActions )
m_bookmarkActions.append( a );
}
plugActionList( "bookmarks_currentdocument", m_bookmarkActions );
-
+
if (factory())
{
const QList<KXMLGUIClient*> clients(factory()->clients());
diff --git a/ui/pageview.cpp b/ui/pageview.cpp
index f1886d3..89a2984 100644
--- a/ui/pageview.cpp
+++ b/ui/pageview.cpp
@@ -70,7 +70,9 @@
#include "pageviewannotator.h"
#include "priorities.h"
#include "toolaction.h"
-//#include "tts.h"
+#ifdef HAVE_SPEECH
+#include "tts.h"
+#endif
#include "videowidget.h"
#include "core/action.h"
#include "core/area.h"
@@ -119,7 +121,9 @@ public:
PageViewPrivate( PageView *qq );
FormWidgetsController* formWidgetsController();
-// OkularTTS* tts();
+#ifdef HAVE_SPEECH
+ OkularTTS* tts();
+#endif
QString selectedText() const;
// the document, pageviewItems and the 'visible cache'
@@ -176,7 +180,9 @@ public:
PageViewMessage * messageWindow; // in pageviewutils.h
bool m_formsVisible;
FormWidgetsController *formsWidgetController;
-// OkularTTS * m_tts;
+#ifdef HAVE_SPEECH
+ OkularTTS * m_tts;
+#endif
QTimer * refreshTimer;
int refreshPage;
@@ -227,6 +233,9 @@ public:
PageViewPrivate::PageViewPrivate( PageView *qq )
: q( qq )
+#ifdef HAVE_SPEECH
+ , m_tts( 0 )
+#endif
{
}
@@ -244,22 +253,22 @@ FormWidgetsController* PageViewPrivate::formWidgetsController()
return formsWidgetController;
}
-//OkularTTS* PageViewPrivate::tts()
-//{
-// if ( !m_tts )
-// {
-// m_tts = new OkularTTS( q );
-// if ( aSpeakStop )
-// {
-// QObject::connect( m_tts, SIGNAL(hasSpeechs(bool)),
-// aSpeakStop, SLOT(setEnabled(bool)) );
-// QObject::connect( m_tts, SIGNAL(errorMessage(QString)),
-// q, SLOT(errorMessage(QString)) );
-// }
-// }
+#ifdef HAVE_SPEECH
+OkularTTS* PageViewPrivate::tts()
+{
+ if ( !m_tts )
+ {
+ m_tts = new OkularTTS( q );
+ if ( aSpeakStop )
+ {
+ QObject::connect( m_tts, SIGNAL(isSpeaking(bool)),
+ aSpeakStop, SLOT(setEnabled(bool)) );
+ }
+ }
-// return m_tts;
-//}
+ return m_tts;
+}
+#endif
/* PageView. What's in this file? -> quick overview.
@@ -305,7 +314,9 @@ PageView::PageView( QWidget *parent, Okular::Document *document )
d->messageWindow = new PageViewMessage(this);
d->m_formsVisible = false;
d->formsWidgetController = 0;
-// d->m_tts = 0;
+#ifdef HAVE_SPEECH
+ d->m_tts = 0;
+#endif
d->refreshTimer = 0;
d->refreshPage = -1;
d->aRotateClockwise = 0;
@@ -410,8 +421,10 @@ PageView::PageView( QWidget *parent, Okular::Document *document )
PageView::~PageView()
{
-// if ( d->m_tts )
-// d->m_tts->stopAllSpeechs();
+#ifdef HAVE_SPEECH
+ if ( d->m_tts )
+ d->m_tts->stopAllSpeechs();
+#endif
// delete the local storage structure
@@ -1074,12 +1087,14 @@ void PageView::updateActionState( bool haspages, bool documentChanged, bool hasf
}
d->aToggleAnnotator->setEnabled( allowAnnotations );
}
+#ifdef HAVE_SPEECH
if ( d->aSpeakDoc )
{
- const bool enablettsactions = haspages ? Okular::Settings::useKTTSD() : false;
+ const bool enablettsactions = haspages ? Okular::Settings::useTTS() : false;
d->aSpeakDoc->setEnabled( enablettsactions );
d->aSpeakPage->setEnabled( enablettsactions );
}
+#endif
if (d->aMouseMagnifier)
d->aMouseMagnifier->setEnabled(d->document->supportsTiles());
}
@@ -2600,7 +2615,7 @@ void PageView::mouseReleaseEvent( QMouseEvent * e )
textToClipboard->setEnabled( false );
textToClipboard->setText( i18n("Copy forbidden by DRM") );
}
- if ( Okular::Settings::useKTTSD() )
+ if ( Okular::Settings::useTTS() )
speakText = menu.addAction( QIcon::fromTheme("text-speak"), i18n( "Speak Text" ) );
if ( copyAllowed )
{
@@ -2665,11 +2680,13 @@ void PageView::mouseReleaseEvent( QMouseEvent * e )
if ( cb->supportsSelection() )
cb->setText( selectedText, QClipboard::Selection );
}
+#ifdef HAVE_SPEECH
else if ( choice == speakText )
{
- // [2] speech selection using KTTSD
-// d->tts()->say( selectedText );
+ // [2] speech selection using TTS
+ d->tts()->say( selectedText );
}
+#endif
}
}
// clear widget selection and invalidate rect
@@ -2850,10 +2867,10 @@ void PageView::mouseReleaseEvent( QMouseEvent * e )
{
QMenu menu( this );
QAction *textToClipboard = menu.addAction( QIcon::fromTheme( "edit-copy" ), i18n( "Copy Text" ) );
- QAction *speakText = 0;
QAction *httpLink = 0;
-// if ( Okular::Settings::useKTTSD() )
-// speakText = menu.addAction( QIcon::fromTheme( "text-speak" ), i18n( "Speak Text" ) );
+ QAction *speakText = 0;
+ if ( Okular::Settings::useTTS() )
+ speakText = menu.addAction( QIcon::fromTheme( "text-speak" ), i18n( "Speak Text" ) );
if ( !d->document->isAllowed( Okular::AllowCopy ) )
{
textToClipboard->setEnabled( false );
@@ -2875,11 +2892,13 @@ void PageView::mouseReleaseEvent( QMouseEvent * e )
{
if ( choice == textToClipboard )
copyTextSelection();
+#ifdef HAVE_SPEECH
else if ( choice == speakText )
{
const QString text = d->selectedText();
-// d->tts()->say( text );
+ d->tts()->say( text );
}
+#endif
else if ( choice == httpLink )
new KRun( QUrl( url ), this );
}
@@ -4938,40 +4957,42 @@ void PageView::slotRefreshPage()
Q_ARG( int, req ) );
}
+#ifdef HAVE_SPEECH
void PageView::slotSpeakDocument()
{
-// QString text;
-// QVector< PageViewItem * >::const_iterator it = d->items.constBegin(), itEnd = d->items.constEnd();
-// for ( ; it < itEnd; ++it )
-// {
-// Okular::RegularAreaRect * area = textSelectionForItem( *it );
-// text.append( (*it)->page()->text( area ) );
-// text.append( '\n' );
-// delete area;
-// }
+ QString text;
+ QVector< PageViewItem * >::const_iterator it = d->items.constBegin(), itEnd = d->items.constEnd();
+ for ( ; it < itEnd; ++it )
+ {
+ Okular::RegularAreaRect * area = textSelectionForItem( *it );
+ text.append( (*it)->page()->text( area ) );
+ text.append( '\n' );
+ delete area;
+ }
-// d->tts()->say( text );
+ d->tts()->say( text );
}
void PageView::slotSpeakCurrentPage()
{
-// const int currentPage = d->document->viewport().pageNumber;
+ const int currentPage = d->document->viewport().pageNumber;
-// PageViewItem *item = d->items.at( currentPage );
-// Okular::RegularAreaRect * area = textSelectionForItem( item );
-// const QString text = item->page()->text( area );
-// delete area;
+ PageViewItem *item = d->items.at( currentPage );
+ Okular::RegularAreaRect * area = textSelectionForItem( item );
+ const QString text = item->page()->text( area );
+ delete area;
-// d->tts()->say( text );
+ d->tts()->say( text );
}
void PageView::slotStopSpeaks()
{
-// if ( !d->m_tts )
-// return;
+ if ( !d->m_tts )
+ return;
-// d->m_tts->stopAllSpeechs();
+ d->m_tts->stopAllSpeechs();
}
+#endif
void PageView::slotAction( Okular::Action *action )
{
diff --git a/ui/pageview.h b/ui/pageview.h
index 4f423d7..f9676fe 100644
--- a/ui/pageview.h
+++ b/ui/pageview.h
@@ -238,9 +238,11 @@ Q_OBJECT
void slotToggleForms();
void slotFormChanged( int pageNumber );
void slotRefreshPage();
+#ifdef HAVE_SPEECH
void slotSpeakDocument();
void slotSpeakCurrentPage();
void slotStopSpeaks();
+#endif
void slotAction( Okular::Action *action );
void externalKeyPressEvent( QKeyEvent *e );
void slotAnnotationWindowDestroyed( QObject *window );
diff --git a/ui/tts.cpp b/ui/tts.cpp
index 6e39e20..8901e09 100644
--- a/ui/tts.cpp
+++ b/ui/tts.cpp
@@ -12,80 +12,35 @@
#include <qdbusservicewatcher.h>
#include <qset.h>
-#include <KLocalisedString>
-#include <kspeech.h>
-#include <ktoolinvocation.h>
-
-#include "kspeechinterface.h"
+#include <KLocalizedString>
/* Private storage. */
class OkularTTS::Private
{
public:
Private( OkularTTS *qq )
- : q( qq ), kspeech( 0 )
- , watcher( "org.kde.kttsd", QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration )
+ : q( qq ), speech( new QTextToSpeech )
{
}
- void setupIface();
- void teardownIface();
-
- OkularTTS *q;
- org::kde::KSpeech* kspeech;
- QSet< int > jobs;
- QDBusServiceWatcher watcher;
-};
-
-void OkularTTS::Private::setupIface()
-{
- if ( kspeech )
- return;
-
- // If KTTSD not running, start it.
- QDBusReply<bool> reply = QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.kttsd" );
- bool kttsdactive = false;
- if ( reply.isValid() )
- kttsdactive = reply.value();
- if ( !kttsdactive )
+ ~Private()
{
- QString error;
- if ( KToolInvocation::startServiceByDesktopName( "kttsd", QStringList(), &error ) )
- {
- emit q->errorMessage( i18n( "Starting Jovie Text-to-Speech service Failed: %1", error ) );
- }
- else
- {
- kttsdactive = true;
- }
+ delete speech;
+ speech = 0;
}
- if ( kttsdactive )
- {
- // creating the connection to the kspeech interface
- kspeech = new org::kde::KSpeech( "org.kde.kttsd", "/KSpeech", QDBusConnection::sessionBus() );
- kspeech->setParent( q );
- kspeech->setApplicationName( "Okular" );
- connect(kspeech, &org::kde::KSpeech::jobStateChanged, q, &OkularTTS::slotJobStateChanged);
- }
-}
-
-void OkularTTS::Private::teardownIface()
-{
- delete kspeech;
- kspeech = 0;
-}
+ OkularTTS *q;
+ QTextToSpeech *speech;
+};
OkularTTS::OkularTTS( QObject *parent )
: QObject( parent ), d( new Private( this ) )
{
- connect(&d->watcher, &QDBusServiceWatcher::serviceUnregistered, this, &OkularTTS::slotServiceUnregistered);
+ connect( d->speech, &QTextToSpeech::stateChanged, this, &OkularTTS::slotSpeechStateChanged);
}
OkularTTS::~OkularTTS()
{
- disconnect( &d->watcher, 0, this, 0 );
-
delete d;
}
@@ -94,50 +49,24 @@ void OkularTTS::say( const QString &text )
if ( text.isEmpty() )
return;
- d->setupIface();
- if ( d->kspeech )
- {
- QDBusReply< int > reply = d->kspeech->say( text, KSpeech::soPlainText );
- if ( reply.isValid() )
- {
- d->jobs.insert( reply.value() );
- emit hasSpeechs( true );
- }
- }
+ d->speech->say( text );
}
void OkularTTS::stopAllSpeechs()
{
- if ( !d->kspeech )
+ if ( !d->speech )
return;
- d->kspeech->removeAllJobs();
-}
-
-void OkularTTS::slotServiceUnregistered( const QString &service )
-{
- if ( service == QLatin1String( "org.kde.kttsd" ) )
- {
- d->teardownIface();
- }
+ d->speech->stop();
}
-void OkularTTS::slotJobStateChanged( const QString &appId, int jobNum, int state )
+void OkularTTS::slotSpeechStateChanged(QTextToSpeech::State state)
{
- // discard non ours job
- if ( appId != QDBusConnection::sessionBus().baseService() || !d->kspeech )
- return;
-
- switch ( state )
- {
- case KSpeech::jsDeleted:
- d->jobs.remove( jobNum );
- emit hasSpeechs( !d->jobs.isEmpty() );
- break;
- case KSpeech::jsFinished:
- d->kspeech->removeJob( jobNum );
- break;
- }
+ if (state == QTextToSpeech::Speaking)
+ emit isSpeaking(true);
+ else
+ emit isSpeaking(false);
}
#include "moc_tts.cpp"
+
diff --git a/ui/tts.h b/ui/tts.h
index cb990e9..8c0fdf6 100644
--- a/ui/tts.h
+++ b/ui/tts.h
@@ -11,6 +11,7 @@
#define _TTS_H_
#include <qobject.h>
+#include <QTextToSpeech>
class OkularTTS : public QObject
{
@@ -22,13 +23,11 @@ class OkularTTS : public QObject
void say( const QString &text );
void stopAllSpeechs();
- signals:
- void hasSpeechs( bool has );
- void errorMessage( const QString &message );
+ public slots:
+ void slotSpeechStateChanged(QTextToSpeech::State state);
- private slots:
- void slotServiceUnregistered( const QString& );
- void slotJobStateChanged( const QString &appId, int jobNum, int state );
+ signals:
+ void isSpeaking( bool speaking );
private:
// private storage