2019-02-24 00:58:25 +00:00
/* OSCAR Help Implementation
2018-06-06 16:03:51 +00:00
*
2024-01-13 20:27:48 +00:00
* Copyright ( c ) 2019 - 2024 The OSCAR Team
2024-02-01 00:14:19 +00:00
* Copyright ( c ) 2018 Mark Watkins
2018-06-06 16:03:51 +00:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of the source code
* for more details . */
2018-06-07 00:09:06 +00:00
# include <QtHelp>
2018-06-06 16:03:51 +00:00
# include <QDebug>
# include <QTimer>
2018-06-09 00:59:16 +00:00
# include <QFile>
# include <QDir>
2018-06-06 16:03:51 +00:00
2018-06-07 05:30:31 +00:00
# include "SleepLib/common.h"
2018-06-09 00:59:16 +00:00
# include "translation.h"
2018-06-06 16:03:51 +00:00
# include "help.h"
# include "ui_help.h"
Help : : Help ( QWidget * parent ) :
QWidget ( parent ) ,
ui ( new Ui : : Help )
{
ui - > setupUi ( this ) ;
2018-06-09 00:59:16 +00:00
QString helpRoot = appResourcePath ( ) + " /Help/ " ;
2019-03-17 19:40:11 +00:00
qDebug ( ) < < " Help root is " + helpRoot ;
2019-03-30 15:24:24 +00:00
QString helpIndex ;
// Use a path in AppData
QCoreApplication : : setOrganizationDomain ( " nightowlsoftware.ca " ) ;
auto path = QStandardPaths : : writableLocation ( QStandardPaths : : AppDataLocation ) ;
if ( path . isEmpty ( ) )
qFatal ( " Cannot determine user data storage location " ) ;
QDir d { path } ;
if ( d . mkpath ( d . absolutePath ( ) ) ) {
qDebug ( ) < < " Help index is in " < < d . absolutePath ( ) ;
helpIndex = d . absolutePath ( ) + " /index.qhc " ;
} else {
qDebug ( ) < < " Could not create path to index directory - " + d . absolutePath ( ) ;
}
2018-06-09 00:59:16 +00:00
QDir dir ( helpRoot ) ;
QStringList nameFilters = QStringList ( " *.qch " ) ;
QStringList helpfiles = dir . entryList ( nameFilters , QDir : : Files | QDir : : Readable ) ;
language = currentLanguage ( ) ;
QString helpFile ;
for ( const QString & file : helpfiles ) {
if ( file . endsWith ( language + " .qch " ) ) {
helpFile = helpRoot + file ;
break ;
}
}
if ( helpFile . isEmpty ( ) & & ( language ! = DefaultLanguage ) ) {
ui - > languageWarningMessage - > setText ( tr ( " Help Files are not yet available for %1 and will display in %2. " ) . arg ( lookupLanguageName ( language ) ) . arg ( lookupLanguageName ( DefaultLanguage ) ) ) ;
language = DefaultLanguage ;
for ( const QString & file : helpfiles ) {
if ( file . endsWith ( language + " .qch " ) ) {
helpFile = helpRoot + file ;
}
break ;
}
}
if ( helpFile . isEmpty ( ) ) {
2018-06-14 08:58:06 +00:00
ui - > languageWarningMessage - > setText ( tr ( " Help files do not appear to be present. " ) ) ;
2018-06-09 00:59:16 +00:00
// Still empty, install is dodgy
// Copy en_US out of resource??
// For now I just don't care, if the user screws up.. tough
}
helpLoaded = false ;
// Delete the crappy qhc so we can generate our own.
2019-03-30 15:24:24 +00:00
if ( QFile : : exists ( helpIndex ) )
QFile : : remove ( helpIndex ) ;
2018-06-09 00:59:16 +00:00
2018-06-12 12:55:44 +00:00
helpEngine = new QHelpEngine ( helpIndex ) ;
2019-02-24 00:58:25 +00:00
helpNamespace = " nightowlsoftware.ca.OSCAR_Guide " ;
2018-06-06 16:03:51 +00:00
2018-06-09 00:59:16 +00:00
if ( ! helpFile . isEmpty ( ) ) {
if ( ! helpEngine - > setupData ( ) ) {
ui - > languageWarningMessage - > setText ( tr ( " HelpEngine did not set up correctly " ) ) ;
2019-03-17 19:40:11 +00:00
qDebug ( ) < < " Help engine Setup Failed " ;
} else for ( auto const & st : helpEngine - > registeredDocumentations ( ) ) {
if ( st = = helpNamespace ) {
qDebug ( ) < < " Already Registered " < < helpFile ;
helpLoaded = true ;
ui - > languageWarning - > setVisible ( false ) ;
}
}
if ( ! helpLoaded ) {
if ( helpEngine - > registerDocumentation ( helpFile ) ) {
qDebug ( ) < < " Registered " < < helpFile ;
helpLoaded = true ;
ui - > languageWarning - > setVisible ( false ) ;
} else {
ui - > languageWarningMessage - > setText ( tr ( " HelpEngine could not register documentation correctly. " ) ) ;
qDebug ( ) < < helpEngine - > error ( ) ;
}
2018-06-06 16:03:51 +00:00
}
2018-06-09 00:59:16 +00:00
}
2018-06-06 16:03:51 +00:00
2018-06-09 00:59:16 +00:00
helpBrowser = new HelpBrowser ( helpEngine ) ;
2018-06-06 16:03:51 +00:00
tabWidget = new QTabWidget ;
tabWidget - > setMaximumWidth ( 250 ) ;
tabWidget - > addTab ( helpEngine - > contentWidget ( ) , tr ( " Contents " ) ) ;
tabWidget - > addTab ( helpEngine - > indexWidget ( ) , tr ( " Index " ) ) ;
2018-06-08 05:43:03 +00:00
resultWidget = new MyTextBrowser ( this ) ;
resultWidget - > setOpenLinks ( false ) ;
tabWidget - > addTab ( resultWidget , tr ( " Search " ) ) ;
2018-06-06 16:03:51 +00:00
ui - > splitter - > insertWidget ( 0 , tabWidget ) ;
ui - > splitter - > insertWidget ( 1 , helpBrowser ) ;
2018-06-09 00:59:16 +00:00
ui - > forwardButton - > setEnabled ( false ) ;
ui - > backButton - > setEnabled ( false ) ;
2018-06-06 16:03:51 +00:00
2018-06-08 05:43:03 +00:00
2018-06-09 00:59:16 +00:00
if ( ! helpLoaded ) {
2019-04-16 17:12:26 +00:00
QString html = " <html><body><div align= \" center \" valign= \" center \" ><img src= \" qrc://icons/logo-md.png \" ><br/><h2> " + tr ( " No documentation available " ) + " </h2></div></body></html> " ;
2018-06-09 00:59:16 +00:00
helpBrowser - > setHtml ( html ) ;
return ;
} else {
QTimer : : singleShot ( 50 , this , SLOT ( startup ( ) ) ) ;
2018-06-08 05:43:03 +00:00
2018-06-09 00:59:16 +00:00
connect ( helpBrowser , SIGNAL ( forwardAvailable ( bool ) ) , this , SLOT ( forwardAvailable ( bool ) ) ) ;
connect ( helpBrowser , SIGNAL ( backwardAvailable ( bool ) ) , this , SLOT ( backwardAvailable ( bool ) ) ) ;
connect ( helpEngine - > contentWidget ( ) , SIGNAL ( linkActivated ( QUrl ) ) , helpBrowser , SLOT ( setSource ( QUrl ) ) ) ;
connect ( helpEngine - > indexWidget ( ) , SIGNAL ( linkActivated ( QUrl , QString ) ) , helpBrowser , SLOT ( setSource ( QUrl ) ) ) ;
2018-06-06 16:03:51 +00:00
2018-06-09 00:59:16 +00:00
connect ( helpEngine - > searchEngine ( ) , SIGNAL ( searchingFinished ( int ) ) , this , SLOT ( on_searchComplete ( int ) ) ) ;
connect ( helpEngine - > searchEngine ( ) , SIGNAL ( indexingFinished ( ) ) , this , SLOT ( indexingFinished ( ) ) ) ;
2018-06-06 16:03:51 +00:00
2018-06-09 00:59:16 +00:00
connect ( resultWidget , SIGNAL ( anchorClicked ( QUrl ) ) , this , SLOT ( requestShowLink ( QUrl ) ) ) ;
2018-06-06 16:03:51 +00:00
2018-06-09 00:59:16 +00:00
searchReady = false ;
helpEngine - > searchEngine ( ) - > reindexDocumentation ( ) ;
helpBrowser - > setSource ( QUrl ( QString ( " qthelp://%1/doc/index.html " ) . arg ( helpNamespace ) ) ) ;
}
2018-06-06 16:03:51 +00:00
}
Help : : ~ Help ( )
{
2018-06-08 05:43:03 +00:00
disconnect ( resultWidget , SIGNAL ( anchorClicked ( QUrl ) ) , this , SLOT ( requestShowLink ( QUrl ) ) ) ;
2018-06-06 16:03:51 +00:00
disconnect ( helpEngine - > searchEngine ( ) , SIGNAL ( indexingFinished ( ) ) , this , SLOT ( indexingFinished ( ) ) ) ;
disconnect ( helpEngine - > searchEngine ( ) , SIGNAL ( searchingFinished ( int ) ) , this , SLOT ( on_searchComplete ( int ) ) ) ;
disconnect ( helpEngine - > contentWidget ( ) , SIGNAL ( linkActivated ( QUrl ) ) , helpBrowser , SLOT ( setSource ( QUrl ) ) ) ;
2018-06-07 01:53:20 +00:00
disconnect ( helpEngine - > indexWidget ( ) , SIGNAL ( linkActivated ( QUrl , QString ) ) , helpBrowser , SLOT ( setSource ( QUrl ) ) ) ;
2018-06-06 16:03:51 +00:00
disconnect ( helpBrowser , SIGNAL ( backwardAvailable ( bool ) ) , this , SLOT ( backwardAvailable ( bool ) ) ) ;
disconnect ( helpBrowser , SIGNAL ( forwardAvailable ( bool ) ) , this , SLOT ( forwardAvailable ( bool ) ) ) ;
delete helpEngine ;
delete ui ;
}
void Help : : startup ( )
{
helpEngine - > contentWidget ( ) - > expandToDepth ( 0 ) ;
}
HelpBrowser : : HelpBrowser ( QHelpEngine * helpEngine , QWidget * parent ) :
QTextBrowser ( parent ) , helpEngine ( helpEngine )
{
}
QVariant HelpBrowser : : loadResource ( int type , const QUrl & name )
{
2018-06-09 00:59:16 +00:00
if ( name . scheme ( ) = = " qthelp " ) {
qDebug ( ) < < " Loading " < < name . toString ( ) ;
return QVariant ( helpEngine - > fileData ( name ) ) ;
} else
// QString path = name.path(QUrl::FullyEncoded).replace("/./","/");
// if (!path.startsWith("/doc")) path="/doc"+path;
// QString urlstr = "qthelp://"+helpNamespace+path;
// QByteArray bytes = helpEngine->fileData(urlstr);
// if (bytes.size()>0) return QVariant(bytes);
2018-06-06 16:03:51 +00:00
2018-06-08 05:43:03 +00:00
if ( type = = QTextDocument : : ImageResource & & name . scheme ( ) . compare ( QLatin1String ( " " ) , Qt : : CaseInsensitive ) = = 0 ) {
2018-06-06 16:03:51 +00:00
static QRegularExpression re ( " ^image/[^;]+;base64,.+={0,2}$ " ) ;
QRegularExpressionMatch match = re . match ( name . path ( ) ) ;
if ( match . hasMatch ( ) )
return QVariant ( ) ;
}
return QTextBrowser : : loadResource ( type , name ) ;
}
void Help : : on_backButton_clicked ( )
{
helpBrowser - > backward ( ) ;
}
void Help : : on_forwardButton_clicked ( )
{
helpBrowser - > forward ( ) ;
}
void Help : : on_homeButton_clicked ( )
{
2018-06-09 00:59:16 +00:00
if ( ! helpLoaded ) return ;
QByteArray index = helpEngine - > fileData ( QUrl ( QString ( " qthelp://%1/doc/index.html " ) . arg ( helpNamespace ) ) ) ;
2018-06-06 16:03:51 +00:00
helpBrowser - > setHtml ( index ) ;
}
2018-06-08 05:43:03 +00:00
void Help : : on_searchComplete ( int count )
2018-06-06 16:03:51 +00:00
{
if ( ! searchReady ) {
2018-06-14 07:25:54 +00:00
QString html = " <h1> " + tr ( " Please wait a bit.. Indexing still in progress " ) + " </h1> " ;
2018-06-06 16:03:51 +00:00
helpBrowser - > setText ( html ) ;
return ;
}
QHelpSearchEngine * search = helpEngine - > searchEngine ( ) ;
QVector < QHelpSearchResult > results = search - > searchResults ( 0 , count ) ;
2018-06-08 05:43:03 +00:00
// ui->searchBar->blockSignals(true);
ui - > searchBar - > setText ( QString ( ) ) ;
// ui->searchBar->blockSignals(false);
2018-06-06 16:03:51 +00:00
2018-06-08 05:43:03 +00:00
QString html = " <html><head><style type= \" text/css \" > "
" a:link, a:visited { color: inherit; text-decoration: none; font-weight: normal;} "
" a:hover { background-color: inherit; color: #ff8888; text-decoration: underline; font-weight: bold; } "
" </style></head><body> " ;
QString queryString ;
# if QT_VERSION < QT_VERSION_CHECK(5,9,0)
QList < QHelpSearchQuery > results = search - > query ( ) ;
if ( results . size ( ) > 0 ) {
queryString = results [ 0 ] . wordList . at ( 0 ) ;
}
# else
queryString = search - > searchInput ( ) ;
# endif
QString a = ( results . size ( ) = = 0 ) ? tr ( " No " ) : QString ( " %1 " ) . arg ( results . size ( ) ) ;
html + = " <font size=+1><b> " + tr ( " %1 result(s) for \" %2 \" " ) . arg ( a ) . arg ( queryString ) + " </b></font> " ;
if ( results . size ( ) > 0 ) html + = " [<font size=-1><a href='clear'> " + tr ( " clear " ) + " </a></font>] " ;
2018-06-06 16:03:51 +00:00
for ( QHelpSearchResult & result : results ) {
2018-06-08 05:43:03 +00:00
QString title = result . url ( ) . toString ( ) . section ( " / " , - 1 ) ;
html + = QString ( " <p><a href= \" %1 \" ><b>%2:</b> %3</a></p> " ) . arg ( result . url ( ) . toString ( ) ) . arg ( title ) . arg ( result . snippet ( ) ) ;
2018-06-06 16:03:51 +00:00
}
2018-06-08 05:43:03 +00:00
html + = " </body></html> " ;
resultWidget - > setText ( html ) ;
tabWidget - > setCurrentWidget ( resultWidget ) ;
2018-06-06 16:03:51 +00:00
}
void Help : : on_searchBar_returnPressed ( )
{
2018-06-09 00:59:16 +00:00
if ( ! helpLoaded ) {
ui - > searchBar - > clear ( ) ;
return ;
}
2018-06-06 16:03:51 +00:00
QHelpSearchEngine * search = helpEngine - > searchEngine ( ) ;
QString str = ui - > searchBar - > text ( ) ;
2018-06-08 04:45:24 +00:00
2018-06-08 05:43:03 +00:00
# if QT_VERSION < QT_VERSION_CHECK(5,9,0)
2018-06-08 04:45:24 +00:00
QList < QHelpSearchQuery > query ;
query . push_back ( QHelpSearchQuery ( QHelpSearchQuery : : FUZZY , QStringList ( str ) ) ) ;
search - > search ( query ) ;
# else
2018-06-06 16:03:51 +00:00
search - > search ( str ) ;
2018-06-08 04:45:24 +00:00
# endif
2018-06-06 16:03:51 +00:00
}
void Help : : indexingFinished ( )
{
searchReady = true ;
}
void Help : : forwardAvailable ( bool b )
{
ui - > forwardButton - > setEnabled ( b ) ;
}
void Help : : backwardAvailable ( bool b )
{
ui - > backButton - > setEnabled ( b ) ;
}
void Help : : requestShowLink ( const QUrl & link )
{
2018-06-08 05:43:03 +00:00
if ( link . toString ( ) = = " clear " ) {
resultWidget - > clear ( ) ;
} else {
helpBrowser - > setSource ( link ) ;
}
2018-06-06 16:03:51 +00:00
}
2018-06-09 00:59:16 +00:00
void Help : : on_languageWarningCheckbox_clicked ( bool checked )
{
ui - > languageWarning - > setVisible ( ! checked ) ;
}