fix merge conflict

This commit is contained in:
Xiao YiFang 2022-06-19 09:46:39 +08:00
commit cea97f5727
100 changed files with 2132 additions and 1897 deletions

View file

@ -1,28 +1,30 @@
# Format Style Options - Created with Clang Power Tools
---
BasedOnStyle: LLVM
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: AcrossComments
AlignEscapedNewlines: Left
AllowAllArgumentsOnNextLine: 'false'
AllowShortBlocksOnASingleLine: 'false'
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
BinPackArguments: 'false'
BinPackParameters: 'false'
BasedOnStyle: LLVM
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Allman
BreakConstructorInitializers: AfterColon
ColumnLimit: '120'
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
ConstructorInitializerIndentWidth: '2'
ContinuationIndentWidth: '2'
MaxEmptyLinesToKeep: '1'
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth : 2
ContinuationIndentWidth: 2
MaxEmptyLinesToKeep: 1
PointerAlignment: Middle
SortIncludes: 'false'
SortUsingDeclarations: 'false'
SortIncludes: false
SortUsingDeclarations: false
SpaceBeforeParens: Never
SpacesInAngles: 'true'
SpacesInParentheses: 'true'
SpacesInSquareBrackets: 'true'
SpacesInAngles: true
SpacesInParentheses: true
SpacesInSquareBrackets: true
UseTab: Never
AlignConsecutiveAssignments: AcrossComments
...

View file

@ -25,7 +25,7 @@ jobs:
strategy:
matrix:
os: [macos-11]
qt_ver: [6.2.4,6.3.0]
qt_ver: [6.2.4,6.3.1]
qt_arch: [clang_64]
env:
targetName: GoldenDict
@ -74,6 +74,13 @@ jobs:
mv ${targetName}.app ./tmp
# --background "installer_background.png"
create-dmg --volname "${targetName} Installer" --volicon "icons/macicon.icns" --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "${targetName}.app" 200 190 --hide-extension "${targetName}.app" --app-drop-link 600 185 --skip-jenkins "${targetName}.dmg" tmp/
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
run: |
@ -82,6 +89,11 @@ jobs:
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -91,7 +103,7 @@ jobs:
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
CHANGELOG="${CHANGELOG//"'"/ }"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
# tag 上传Release
- name: uploadRelease
uses: svenstaro/upload-release-action@v2
@ -119,4 +131,5 @@ jobs:
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.vars.outputs.COMMIT_SUMMARY }}
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}

View file

@ -1,5 +1,7 @@
name: macos-PR-check
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:

View file

@ -75,7 +75,12 @@ jobs:
mv ${targetName}.app ./tmp
# --background "installer_background.png"
create-dmg --volname "${targetName} Installer" --volicon "icons/macicon.icns" --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "${targetName}.app" 200 190 --hide-extension "${targetName}.app" --app-drop-link 600 185 --skip-jenkins "${targetName}.dmg" tmp/
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
@ -85,6 +90,11 @@ jobs:
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -122,4 +132,5 @@ jobs:
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.vars.outputs.COMMIT_SUMMARY }}
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}

View file

@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
qt_ver: [6.2.4,6.3.0]
qt_ver: [6.3.1]
qt_arch: [gcc_64]
env:
version: 22.5.21
@ -65,30 +65,39 @@ jobs:
qmake CONFIG+=release PREFIX=/usr CONFIG+=zim_support CONFIG+=chinese_conversion_support
make INSTALL_ROOT=appdir -j`nproc` install; find appdir/
ls -al appdir
#copy missing shared dll to appdir.
mkdir -p appdir/usr/lib
cp $(ldd appdir/usr/bin/goldendict | grep -o '\W/[^ ]*' |grep gobject ) appdir/usr/lib
cp $(ldd appdir/usr/bin/goldendict | grep -o '\W/[^ ]*' |grep libpango ) appdir/usr/lib
# mkdir -p appdir/usr/lib
# cp $(ldd appdir/usr/bin/goldendict | grep -o '\W/[^ ]*' |grep gobject ) appdir/usr/lib
# cp $(ldd appdir/usr/bin/goldendict | grep -o '\W/[^ ]*' |grep libpango ) appdir/usr/lib
- name: Build AppImage
run: |
wget -c -nv "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage
wget -c -nv "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
chmod a+x linuxdeploy-x86_64.AppImage
./linuxdeploy-x86_64.AppImage --appdir appdir --output appimage --plugin qt -i redist/icons/goldendict.png -d redist/org.goldendict.GoldenDict.desktop
# - uses: actions/upload-artifact@v2
# with:
# name: AppImage
# path: './*.AppImage*'
wget -c https://github.com/$(wget -q https://github.com/probonopd/go-appimage/releases -O - | grep "appimagetool-.*-x86_64.AppImage" | head -n 1 | cut -d '"' -f 2)
chmod +x appimagetool-*.AppImage
./appimagetool-*.AppImage -s deploy appdir/usr/share/applications/*.desktop # Bundle EVERYTHING
# ./linuxdeploy-x86_64.AppImage --appdir appdir --output appimage --plugin qt -i redist/icons/goldendict.png -d redist/org.goldendict.GoldenDict.desktop
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
run: |
echo "::set-output name=sha_short::$(git rev-parse --short=8 HEAD)"
echo "::set-output name=release_date::$(date +'%Y%m%d')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=appname::$(ls *.AppImage*)"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
echo "::set-output name=appname::$(ls *.AppImage*)"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -98,7 +107,7 @@ jobs:
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
CHANGELOG="${CHANGELOG//"'"/ }"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
- name: uploadRelease
# if: startsWith(github.event.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2
@ -126,4 +135,5 @@ jobs:
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.vars.outputs.COMMIT_SUMMARY }}
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}

View file

@ -1,5 +1,7 @@
name: Ubuntu-PR-check
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:

View file

@ -77,15 +77,27 @@ jobs:
chmod a+x linuxdeploy-x86_64.AppImage
./linuxdeploy-x86_64.AppImage --appdir appdir --output appimage --plugin qt -i redist/icons/goldendict.png -d redist/org.goldendict.GoldenDict.desktop
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
run: |
echo "::set-output name=sha_short::$(git rev-parse --short=8 HEAD)"
echo "::set-output name=release_date::$(date +'%Y%m%d')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=appname::$(ls *.AppImage*)"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
echo "::set-output name=appname::$(ls *.AppImage*)"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -95,7 +107,7 @@ jobs:
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
CHANGELOG="${CHANGELOG//"'"/ }"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
- name: uploadRelease
# if: startsWith(github.event.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2
@ -123,4 +135,5 @@ jobs:
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.vars.outputs.COMMIT_SUMMARY }}
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}

View file

@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
os: [windows-2019]
qt_ver: [6.2.4,6.3.0]
qt_ver: [6.2.4,6.3.1]
qt_arch: [win64_msvc2019_64]
env:
targetName: GoldenDict.exe
@ -52,15 +52,28 @@ jobs:
with:
fetch-depth: 0
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
shell: bash
run: |
echo "::set-output name=sha_short::$(git rev-parse --short=8 HEAD)"
echo "::set-output name=release_date::$(date +'%Y%m%d')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
shell: bash
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -70,7 +83,7 @@ jobs:
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
CHANGELOG="${CHANGELOG//"'"/ }"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
# # msvc编译
- uses: ilammy/msvc-dev-cmd@v1
@ -128,6 +141,11 @@ jobs:
Qt6.X(Universal Build)
Qt5.15.2(Intel Kind)
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}
- name: upload goldendict.exe only
# if: startsWith(github.event.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2

View file

@ -1,5 +1,7 @@
name: Windows-PR-check
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:

View file

@ -54,15 +54,28 @@ jobs:
with:
fetch-depth: 0
- name: Generate changelog
if: ${{!env.prerelease}}
id: changelog1
uses: metcalfc/changelog-generator@v3.0.0
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
id: vars
shell: bash
run: |
echo "::set-output name=sha_short::$(git rev-parse --short=8 HEAD)"
echo "::set-output name=release_date::$(date +'%Y%m%d')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_time::$(date +'%H%M%S')"
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
echo "::set-output name=release_hm::$(date +'%y%m%d')"
- name: changelog
if: $${{env.prerelease}}
id: changelog2
shell: bash
run: |
previousTag=$(git tag --sort=-creatordate | sed -n 2p)
echo "previousTag : $previousTag"
@ -72,7 +85,7 @@ jobs:
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
CHANGELOG="${CHANGELOG//"'"/ }"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
echo "::set-output name=COMMIT_SUMMARY::$(echo "$CHANGELOG")"
- uses: ilammy/msvc-dev-cmd@v1
# msvc编译
- name: msvc-build goldendict
@ -127,7 +140,8 @@ jobs:
auto built by github action. use on your on risk:-)
CHANGES:
${{ steps.vars.outputs.COMMIT_SUMMARY }}
${{ steps.changelog1.outputs.changelog }}
${{ steps.changelog2.outputs.COMMIT_SUMMARY }}
- name: upload goldendict.exe only
# if: startsWith(github.event.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2

View file

@ -3,6 +3,17 @@
## Until to now
- **CLEANING OLD/USELESS CODE**
- remove Runnable Class in dsl, zim , epwing etc files.
- add "send to anki"
- right context menu actions, remove nonsense character like `OBJ`,punctuation etc.
- epwing remove duplicate entries when index.
- replace throw() with noexcept
- replace string(***constData) with toStdString
- add built-in support for entry links in javascript files
## Until 2022-5-21
- fix a zim about:blank#block [issue](https://github.com/goldendict/goldendict/issues/1472#issuecomment-1086776611)
- add fallback font family configuration for dictionary through preference dialog.
- fix mdx (compact html) display error on the last item.

16
aard.cc
View file

@ -239,16 +239,16 @@ class AardDictionary: public BtreeIndexing::BtreeDictionary
~AardDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -284,7 +284,7 @@ class AardDictionary: public BtreeIndexing::BtreeDictionary
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -338,7 +338,7 @@ AardDictionary::~AardDictionary()
df.close();
}
void AardDictionary::loadIcon() throw()
void AardDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -429,7 +429,7 @@ void AardDictionary::loadArticle( quint32 address,
while( 1 )
{
articleText = string( QObject::tr( "Article loading error" ).toUtf8().constData() );
articleText = QObject::tr( "Article loading error" ).toStdString();
try
{
Mutex::Lock _( aardMutex );
@ -521,7 +521,7 @@ void AardDictionary::loadArticle( quint32 address,
articleText = convert( articleText );
}
else
articleText = string( QObject::tr( "Article decoding error" ).toUtf8().constData() );
articleText = QObject::tr( "Article decoding error" ).toStdString();
// See Issue #271: A mechanism to clean-up invalid HTML cards.
string cleaner = "</font>""</font>""</font>""</font>""</font>""</font>"

View file

@ -23,10 +23,8 @@ About::About( QWidget * parent ): QDialog( parent )
ui.version->setText( version );
#if defined (_MSC_VER)
QString compilerVersion = QString( "Visual C++ %1.%2.%3" )
.arg( GD_CXX_MSVC_MAJOR )
.arg( GD_CXX_MSVC_MINOR )
.arg( GD_CXX_MSVC_BUILD );
QString compilerVersion = QString( "Visual C++ Compiler: %1" )
.arg( _MSC_FULL_VER );
#elif defined (__clang__) && defined (__clang_version__)
QString compilerVersion = QLatin1String( "Clang " ) + QLatin1String( __clang_version__ );
#else

View file

@ -7,20 +7,6 @@
#include "ui_about.h"
#include <QDialog>
// Microsoft Visual C++ version
#if defined (_MSC_VER)
// how many digits does the build number have?
# if _MSC_FULL_VER / 10000 == _MSC_VER
# define GD_CXX_MSVC_BUILD (_MSC_FULL_VER % 10000) // four digits
# elif _MSC_FULL_VER / 100000 == _MSC_VER
# define GD_CXX_MSVC_BUILD (_MSC_FULL_VER % 100000) // five digits
# else
# define GD_CXX_MSVC_BUILD 0
# endif
# define GD_CXX_MSVC_MAJOR (_MSC_VER/100-6)
# define GD_CXX_MSVC_MINOR (_MSC_VER%100)
#endif
class About: public QDialog
{
Q_OBJECT

85
ankiconnector.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "ankiconnector.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include "utils.hh"
AnkiConnector::AnkiConnector( QObject * parent, Config::Class const & _cfg ) : QObject{ parent }, cfg( _cfg )
{
mgr = new QNetworkAccessManager( this );
connect( mgr, &QNetworkAccessManager::finished, this, &AnkiConnector::finishedSlot );
}
void AnkiConnector::sendToAnki( QString const & word, QString const & text )
{
//for simplicity. maybe use QJsonDocument in future?
QString postTemplate = QString( "{"
"\"action\": \"addNote\","
"\"version\": 6,"
"\"params\": {"
" \"note\": {"
" \"deckName\": \"%1\","
" \"modelName\": \"%2\","
" \"fields\":%3,"
" \"options\": {"
" \"allowDuplicate\": true"
" },"
" \"tags\": []"
"}"
"}"
"}"
"" );
QJsonObject fields;
fields.insert( "Front", word );
fields.insert( "Back", text );
QString postData = postTemplate.arg( cfg.preferences.ankiConnectServer.deck,
cfg.preferences.ankiConnectServer.model,
Utils::json2String( fields ) );
// qDebug().noquote() << postData;
QUrl url;
url.setScheme( "http" );
url.setHost( cfg.preferences.ankiConnectServer.host );
url.setPort( cfg.preferences.ankiConnectServer.port );
QNetworkRequest request( url );
request.setTransferTimeout( 3000 );
// request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy );
request.setHeader( QNetworkRequest::ContentTypeHeader, "applicaion/json" );
auto reply = mgr->post( request, postData.toUtf8() );
connect( reply,
&QNetworkReply::errorOccurred,
this,
[ this ]( QNetworkReply::NetworkError e )
{
qWarning() << e;
emit this->errorText( tr( "anki: post to anki failed" ) );
} );
}
void AnkiConnector::finishedSlot( QNetworkReply * reply )
{
if( reply->error() == QNetworkReply::NoError )
{
QByteArray bytes = reply->readAll();
QJsonDocument json = QJsonDocument::fromJson( bytes );
auto obj = json.object();
if( obj.size() != 2 || !obj.contains( "error" ) || !obj.contains( "result" ) ||
obj[ "result" ].toString().isEmpty() )
{
emit errorText( QObject::tr( "anki: post to anki failed" ) );
}
QString result = obj[ "result" ].toString();
qDebug() << "anki result:" << result;
emit errorText( tr( "anki: post to anki success" ) );
}
else
{
qDebug() << "anki connect error" << reply->errorString();
emit errorText( "anki:" + reply->errorString() );
}
reply->deleteLater();
}

28
ankiconnector.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef ANKICONNECTOR_H
#define ANKICONNECTOR_H
#include "config.hh"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QObject>
class AnkiConnector : public QObject
{
Q_OBJECT
public:
explicit AnkiConnector( QObject * parent, Config::Class const & cfg );
void sendToAnki( QString const & word, QString const & text );
private:
QNetworkAccessManager * mgr;
Config::Class const & cfg;
public :
signals:
void errorText( QString const & );
private slots:
void finishedSlot(QNetworkReply * reply);
};
#endif // ANKICONNECTOR_H

View file

@ -95,7 +95,7 @@ body
.gddictnamebodyseparator
{
display: inline-block;
width: 100%;
clear: both;
border-top: 1px solid #92b0dd;
margin-bottom: 1em;
}

View file

@ -24,24 +24,19 @@ a:hover
background: white;
}
/* Dictionary's name heading */
.gddictname
{
border: 1px dotted black; padding: 0.2em; padding-left: 0.5em;
margin-top: 1.2em; margin-bottom: 0.1em; font-weight: bold; font-size: 14px;
background: #87CEEB;
}
/* The 'From ' string which preceeds dictionary name in the heading */
.gdfromprefix
{
display: none;
}
/* Dictionary's name heading */
.gddictname
{
padding: 0.2em; padding-left: 0.5em;
margin-bottom: 0.1em;
font-size: 14px;
font-weight: normal;
float: right;
border: 1px solid white;
margin-top: 7px;

View file

@ -1,10 +1,14 @@
/******** Global, non-dictionary-specific classes ***********/
html {
height: 100%;
}
body
{
background: #fefdeb;
font-family: Tahoma, Verdana, "Lucida Sans Unicode", sans-serif;
height: 100%;
}
/* This stylesheet is used to highligh current selection when doing a search.
@ -38,6 +42,16 @@ pre
/*background: #ffffdd;*/
}
.gddicttitle
{
user-select: none;
}
.gddictnamebodyseparator
{
clear: both;
}
/* The 'From ' string which precedes dictionary name in the heading */
.gdfromprefix
{
@ -55,8 +69,8 @@ pre
background: #fefdeb;
/*fix for invalid blg*/
font-style:normal;
content-visibility:auto;
contain-intrinsic-size:400px;
content-visibility: auto;
contain-intrinsic-size: 600px;
}
/* CSS trick to prevent the floating elements to overflow
@ -522,7 +536,7 @@ div.xdxf
/************* MDict dictionaries **************/
.mdict
{
margin-top: 1em;
}
.mdict a[name]
@ -914,7 +928,6 @@ div.xdxf
left: 0px;
width: 0px;
background-color: white;
background-color: Window;
border-style: solid;
border-color: #AAAAAA;
border-width: 1px;
@ -934,9 +947,7 @@ div.xdxf
.mwiki td.os-suggest-result, .mwiki td.os-suggest-result-hl {
white-space: nowrap;
background-color: white;
background-color: Window;
color: black;
color: WindowText;
padding: 2px;
}
.mwiki td.os-suggest-result-hl,
@ -944,12 +955,6 @@ div.xdxf
background-color: #4C59A6;
color: white;
}
.mwiki td.os-suggest-result-hl {
/* System colors are misimplemented in Safari 3.0 and earlier,
making highlighted text illegible... */
background-color: Highlight;
color: HighlightText;
}
.mwiki .os-suggest-toggle {
position: relative;

View file

@ -3,15 +3,15 @@
#if (QT_VERSION > QT_VERSION_CHECK(6,0,0))
#include <QWebEngineContextMenuRequest>
#endif
ArticleInspector::ArticleInspector( QWidget * parent ) : QWidget( parent, Qt::WindowType::Window )
ArticleInspector::ArticleInspector( QWidget * parent ) : QWidget( parent, Qt::WindowType::Window ),firstTimeOpened(false)
{
setWindowTitle(tr("Inspect"));
setAttribute( Qt::WidgetAttribute::WA_DeleteOnClose, false );
QVBoxLayout * v = new QVBoxLayout( this );
v->setSpacing( 0 );
v->setContentsMargins( 0, 0, 0, 0 );
inspectView = new QWebEngineView( this );
v->addWidget( inspectView );
viewContainer = new QWebEngineView( this );
v->addWidget( viewContainer );
resize(800,600);
}
@ -19,22 +19,26 @@ ArticleInspector::ArticleInspector( QWidget * parent ) : QWidget( parent, Qt::Wi
void ArticleInspector::setInspectPage( QWebEngineView * view )
{
auto page=view->page();
this->inspectedPage = page;
page->setDevToolsPage( inspectView->page() );
viewContainer->page()->setInspectedPage(page);
#if( QT_VERSION > QT_VERSION_CHECK( 6, 0, 0 ) )
// without this line, application will crash on qt6.2 ,see https://bugreports.qt.io/browse/QTBUG-101724
if( view->lastContextMenuRequest() )
if( view->lastContextMenuRequest() && firstTimeOpened )
{
page->triggerAction( QWebEnginePage::InspectElement );
}
if( !firstTimeOpened )
{
firstTimeOpened = true;
}
#else
page->triggerAction( QWebEnginePage::InspectElement );
#endif
raise();
show();
}
void ArticleInspector::closeEvent( QCloseEvent * )
{
inspectedPage->setDevToolsPage( nullptr );
viewContainer->page()->setInspectedPage(nullptr);
}

View file

@ -9,14 +9,15 @@
class ArticleInspector : public QWidget
{
Q_OBJECT
QWebEngineView * inspectView = nullptr;
QWebEnginePage * inspectedPage = nullptr;
QWebEngineView * viewContainer = nullptr;
public:
ArticleInspector( QWidget * parent = nullptr );
void setInspectPage( QWebEngineView * view);
private:
//used to record if the devtool was first time opened.
//if right click on the webpage and open inspect page on the first time ,the application has great possiblity to hang forever.
bool firstTimeOpened;
virtual void closeEvent( QCloseEvent * );
};

View file

@ -465,7 +465,7 @@ void ArticleRequest::altSearchFinished()
if ( altSearches.empty() )
{
#ifdef QT_DEBUG
qDebug( "alts finished\n" );
qDebug( "alts finished" );
#endif
// They all've finished! Now we can look up bodies
@ -534,7 +534,7 @@ void ArticleRequest::bodyFinished()
if ( bodyDone )
return;
GD_DPRINTF( "some body finished\n" );
GD_DPRINTF( "some body finished" );
bool wasUpdated = false;
@ -546,7 +546,7 @@ void ArticleRequest::bodyFinished()
{
// Good
GD_DPRINTF( "one finished.\n" );
GD_DPRINTF( "one finished." );
Dictionary::DataRequest & req = *bodyRequests.front();
@ -672,13 +672,13 @@ void ArticleRequest::bodyFinished()
foundAnyDefinitions = true;
}
GD_DPRINTF( "erasing..\n" );
GD_DPRINTF( "erasing.." );
bodyRequests.pop_front();
GD_DPRINTF( "erase done..\n" );
GD_DPRINTF( "erase done.." );
}
else
{
GD_DPRINTF( "one not finished.\n" );
GD_DPRINTF( "one not finished." );
break;
}
}

View file

@ -8,6 +8,7 @@
#include "gddebug.hh"
#include "utils.hh"
#include <QNetworkAccessManager>
#include "globalbroadcaster.h"
using std::string;
@ -131,22 +132,11 @@ using std::string;
emit errorOccurred( code );
}
// void AllowFrameReply::readDataFromBase()
// {
//// QByteArray data;
//// data.resize( baseReply->bytesAvailable() );
//// baseReply->read( data.data(), data.size() );
//// buffer += data;
// emit readyRead();
// }
qint64 AllowFrameReply::readData( char * data, qint64 maxSize )
{
auto bytesAvailable= baseReply->bytesAvailable();
qint64 size = qMin( maxSize, bytesAvailable );
baseReply->read( data, size );
// memcpy( data, buffer.data(), size );
// buffer.remove( 0, size );
return size;
}
@ -209,11 +199,8 @@ QNetworkReply * ArticleNetworkAccessManager::getArticleReply( QNetworkRequest co
QUrl refererUrl = QUrl::fromEncoded( referer );
//GD_DPRINTF( "Considering %s vs %s\n", getHostBase( req.url() ).toUtf8().data(),
// getHostBase( refererUrl ).toUtf8().data() );
if ( !url.host().endsWith( refererUrl.host() ) &&
getHostBase( url ) != getHostBase( refererUrl ) && !url.scheme().startsWith("data") )
getHostBaseFromUrl( url ) != getHostBaseFromUrl( refererUrl ) && !url.scheme().startsWith("data") )
{
gdWarning( "Blocking element \"%s\" due to not same domain", url.toEncoded().data() );
@ -265,9 +252,9 @@ QNetworkReply * ArticleNetworkAccessManager::getArticleReply( QNetworkRequest co
sptr< Dictionary::DataRequest > ArticleNetworkAccessManager::getResource(
QUrl const & url, QString & contentType )
{
GD_DPRINTF( "getResource: %ls\n", url.toString().toStdWString().c_str() );
GD_DPRINTF( "scheme: %ls\n", url.scheme().toStdWString().c_str() );
GD_DPRINTF( "host: %ls\n", url.host().toStdWString().c_str() );
GD_DPRINTF( "getResource: %ls", url.toString().toStdWString().c_str() );
GD_DPRINTF( "scheme: %ls", url.scheme().toStdWString().c_str() );
GD_DPRINTF( "host: %ls", url.host().toStdWString().c_str() );
if ( url.scheme() == "gdlookup" )
{
@ -460,7 +447,7 @@ qint64 ArticleResourceReply::readData( char * out, qint64 maxSize )
qint64 left = avail - alreadyRead;
qint64 toRead = maxSize < left ? maxSize : left;
GD_DPRINTF( "====reading %d bytes\n", (int)toRead );
GD_DPRINTF( "====reading %d bytes", (int)toRead );
try
{
@ -468,7 +455,7 @@ qint64 ArticleResourceReply::readData( char * out, qint64 maxSize )
}
catch( std::exception & e )
{
qWarning( "getDataSlice error: %s\n", e.what() );
qWarning( "getDataSlice error: %s", e.what() );
}
alreadyRead += toRead;
@ -526,6 +513,16 @@ void LocalSchemeHandler::requestStarted(QWebEngineUrlRequestJob *requestJob)
QNetworkRequest request;
request.setUrl( url );
//all the url reached here must be either gdlookup or bword scheme.
auto [valid, word] = Utils::Url::getQueryWord( url );
// or the condition can be (!queryWord.first || word.isEmpty())
// ( queryWord.first && word.isEmpty() ) is only part of the above condition.
if( valid && word.isEmpty() )
{
// invalid gdlookup url.
return;
}
QNetworkReply * reply = this->mManager.getArticleReply( request );
connect( reply, &QNetworkReply::finished, requestJob, [ = ]() { requestJob->reply( "text/html", reply ); } );
connect( requestJob, &QObject::destroyed, reply, &QObject::deleteLater );

View file

@ -325,6 +325,7 @@ ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, Au
settings->defaultSettings()->setAttribute( QWebEngineSettings::PluginsEnabled, cfg.preferences.enableWebPlugins );
settings->defaultSettings()->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
settings->defaultSettings()->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
settings->defaultSettings()->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
#else
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
settings->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
@ -332,6 +333,7 @@ ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, Au
settings->setAttribute( QWebEngineSettings::PluginsEnabled, cfg.preferences.enableWebPlugins );
settings->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
settings->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
settings->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
#endif
expandOptionalParts = cfg.preferences.alwaysExpandOptionalParts;
@ -348,6 +350,11 @@ ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, Au
channel = new QWebChannel(ui.definition->page());
agent = new ArticleViewAgent(this);
attachWebChannelToHtml();
ankiConnector = new AnkiConnector( this, cfg );
connect( ankiConnector,
&AnkiConnector::errorText,
this,
[ this ]( QString const & errorText ) { emit statusBarMessage( errorText ); } );
}
// explicitly report the minimum size, to avoid
@ -395,6 +402,12 @@ void ArticleView::showDefinition( Config::InputPhrase const & phrase, unsigned g
if ( scrollTo.size() )
Utils::Url::addQueryItem( req, "scrollto", scrollTo );
if( delayedHighlightText.size() )
{
Utils::Url::addQueryItem( req, "regexp", delayedHighlightText );
delayedHighlightText.clear();
}
Contexts::Iterator pos = contexts.find( "gdanchor" );
if( pos != contexts.end() )
{
@ -422,8 +435,7 @@ void ArticleView::showDefinition( Config::InputPhrase const & phrase, unsigned g
if ( mutedDicts.size() )
Utils::Url::addQueryItem( req, "muted", mutedDicts );
// Update both histories (pages history and headwords history)
saveHistoryUserData();
// Update headwords history
emit sendWordToHistory( phrase.phrase );
// Any search opened is probably irrelevant now
@ -434,7 +446,7 @@ void ArticleView::showDefinition( Config::InputPhrase const & phrase, unsigned g
emit setExpandMode( expandOptionalParts );
ui.definition->load( req );
load( req );
//QApplication::setOverrideCursor( Qt::WaitCursor );
ui.definition->setCursor( Qt::WaitCursor );
@ -472,8 +484,7 @@ void ArticleView::showDefinition( QString const & word, QStringList const & dict
if( ignoreDiacritics )
Utils::Url::addQueryItem( req, "ignore_diacritics", "1" );
// Update both histories (pages history and headwords history)
saveHistoryUserData();
// Update headwords history
emit sendWordToHistory( word );
// Any search opened is probably irrelevant now
@ -484,11 +495,15 @@ void ArticleView::showDefinition( QString const & word, QStringList const & dict
emit setExpandMode( expandOptionalParts );
ui.definition->load( req );
load( req );
ui.definition->setCursor( Qt::WaitCursor );
}
void ArticleView::sendToAnki(QString const & word, QString const & text ){
ankiConnector->sendToAnki(word,text);
}
void ArticleView::showAnticipation()
{
ui.definition->setHtml( "" );
@ -520,13 +535,6 @@ void ArticleView::loadFinished( bool result )
// Expand collapsed article if only one loaded
ui.definition->page()->runJavaScript( QString( "gdCheckArticlesNumber();" ) );
// Jump to current article after page reloading
if( !articleToJump.isEmpty() )
{
setCurrentArticle( articleToJump, true );
articleToJump.clear();
}
if( !Utils::Url::queryItemValue( url, "gdanchor" ).isEmpty() )
{
QString anchor = QUrl::fromPercentEncoding( Utils::Url::encodedQueryItemValue( url, "gdanchor" ) );
@ -641,18 +649,18 @@ void ArticleView::jumpToDictionary( QString const & id, bool force )
}
}
void ArticleView::setCurrentArticle( QString const & id, bool moveToIt )
bool ArticleView::setCurrentArticle( QString const & id, bool moveToIt )
{
if ( !isScrollTo( id ) )
return; // Incorrect id
return false; // Incorrect id
if ( !ui.definition->isVisible() )
return; // No action on background page, scrollIntoView there don't work
return false; // No action on background page, scrollIntoView there don't work
if(moveToIt){
QString dictId = id.mid( 7 );
if( dictId.isEmpty() )
return;
return false;
QString script = QString( "var elem=document.getElementById('%1'); "
"if(elem!=undefined){elem.scrollIntoView(true);} gdMakeArticleActive('%2',true);" )
.arg( id, dictId );
@ -660,6 +668,7 @@ void ArticleView::setCurrentArticle( QString const & id, bool moveToIt )
ui.definition->page()->runJavaScript( script );
setActiveArticleId( dictId );
}
return true;
}
void ArticleView::selectCurrentArticle()
@ -696,45 +705,26 @@ void ArticleView::tryMangleWebsiteClickedUrl( QUrl & url, Contexts & contexts )
{
if( framed )
{
// QVariant result = runJavaScriptSync( ui.definition->page(), "gdLastUrlText" );
QVariant result;
if( result.type() == QVariant::String )
{
// Looks this way
contexts[ dictionaryIdFromScrollTo( ca ) ] = QString::fromLatin1( url.toEncoded() );
QUrl target;
QString queryWord = result.toString();
// Empty requests are treated as no request, so we work this around by
// adding a space.
if( queryWord.isEmpty() )
queryWord = " ";
target.setScheme( "gdlookup" );
target.setHost( "localhost" );
target.setPath( "/" + queryWord );
url = target;
}
// no need to translate website internal url to gd builtin url
// and lack the formulation to convert them.
qDebug() << "in the website with url:" << url;
}
} );
}
}
void ArticleView::updateCurrentArticleFromCurrentFrame( QWebEnginePage * frame ,QPoint * point)
{
}
void ArticleView::saveHistoryUserData()
{
ui.definition->setProperty("sx", ui.definition->page()->scrollPosition().x());
ui.definition->setProperty("sy", ui.definition->page()->scrollPosition().y());
}
void ArticleView::load( QUrl const & url )
{
saveHistoryUserData();
ui.definition->load( url );
}
void ArticleView::cleanupTemp()
{
QSet< QString >::iterator it = desktopOpenedTempFiles.begin();
@ -1088,8 +1078,6 @@ void ArticleView::linkClicked( QUrl const & url_ )
if( kmod & Qt::AltModifier )
return;
updateCurrentArticleFromCurrentFrame();
QUrl url( url_ );
Contexts contexts;
@ -1122,22 +1110,29 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
audioPlayer->stop();
qDebug() << "open link url:" << url;
auto [valid, word] = Utils::Url::getQueryWord( url );
if( valid && word.isEmpty() )
{
// invalid gdlookup url.
return;
}
Contexts contexts( contexts_ );
if( url.scheme().compare( "gdpicture" ) == 0 )
ui.definition->load( url );
load( url );
else
if ( url.scheme().compare( "bword" ) == 0 )
if ( url.scheme().compare( "bword" ) == 0 || url.scheme().compare( "entry" ) == 0 )
{
if( Utils::Url::hasQueryItem( ref, "dictionaries" ) )
{
QStringList dictsList = Utils::Url::queryItemValue( ref, "dictionaries" )
.split( ",", Qt::SkipEmptyParts );
showDefinition( url.path(), dictsList, QRegExp(), getGroup( ref ), false );
showDefinition( word, dictsList, QRegExp(), getGroup( ref ), false );
}
else
showDefinition( url.path(),
showDefinition( word,
getGroup( ref ), scrollTo, contexts );
}
else
@ -1160,16 +1155,6 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
return;
}
QString word;
if( Utils::Url::hasQueryItem( url, "word" ) )
{
word=Utils::Url::queryItemValue (url,"word");
}
else{
word=url.path ().mid (1);
}
QString newScrollTo( scrollTo );
if( Utils::Url::hasQueryItem( url, "dict" ) )
{
@ -1583,9 +1568,7 @@ void ArticleView::updateMutedContents()
if ( mutedDicts.size() )
Utils::Url::addQueryItem( currentUrl, "muted", mutedDicts );
saveHistoryUserData();
ui.definition->load( currentUrl );
load( currentUrl );
//QApplication::setOverrideCursor( Qt::WaitCursor );
ui.definition->setCursor( Qt::WaitCursor );
@ -1609,6 +1592,11 @@ void ArticleView::setSelectionBySingleClick( bool set )
ui.definition->setSelectionBySingleClick( set );
}
void ArticleView::setDelayedHighlightText(QString const & text)
{
delayedHighlightText = text;
}
void ArticleView::back()
{
// Don't allow navigating back to page 0, which is usually the initial
@ -1626,9 +1614,14 @@ void ArticleView::forward()
ui.definition->forward();
}
void ArticleView::reload()
{
ui.definition->reload();
}
void ArticleView::hasSound( const std::function< void( bool ) > & callback )
{
ui.definition->page()->runJavaScript( "gdAudioLinks.first",
ui.definition->page()->runJavaScript( "if(typeof(gdAudioLinks)!=\"undefined\") gdAudioLinks.first",
[ callback ]( const QVariant & v )
{
bool has = false;
@ -1713,14 +1706,13 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
{
// Is that a link? Is there a selection?
QWebEnginePage* r=ui.definition->page();
updateCurrentArticleFromCurrentFrame(ui.definition->page(), const_cast<QPoint *>(& pos));
QMenu menu( this );
QAction * followLink = 0;
QAction * followLinkExternal = 0;
QAction * followLinkNewTab = 0;
QAction * lookupSelection = 0;
QAction * sendToAnkiAction = 0 ;
QAction * lookupSelectionGr = 0;
QAction * lookupSelectionNewTab = 0;
QAction * lookupSelectionNewTabGr = 0;
@ -1730,6 +1722,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
QAction * sendWordToInputLineAction = 0;
QAction * saveImageAction = 0;
QAction * saveSoundAction = 0;
QAction * saveBookmark = 0;
#if( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
const QWebEngineContextMenuData * menuData = &(r->contextMenuData());
@ -1788,7 +1781,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
}
QString selectedText = ui.definition->selectedText();
QString text = selectedText.trimmed();
QString text = Utils::trimNonChar( selectedText );
if ( text.size() && text.size() < 60 )
{
@ -1850,6 +1843,21 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
}
}
if(text.size())
{
// avoid too long in the menu ,use left 30 characters.
saveBookmark = new QAction( tr( "Save &Bookmark \"%1...\"" ).arg( text.left( 30 ) ), &menu );
menu.addAction( saveBookmark );
}
// add anki menu
if( !text.isEmpty() && cfg.preferences.ankiConnectServer.enabled )
{
QString txt = ui.definition->title();
sendToAnkiAction = new QAction( tr( "&Send \"%1\" to anki with selected text." ).arg( txt ), &menu );
menu.addAction( sendToAnkiAction );
}
if( text.isEmpty() && !cfg.preferences.storeHistory)
{
QString txt = ui.definition->title();
@ -1941,7 +1949,15 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
QDesktopServices::openUrl( targetUrl );
else
if ( result == lookupSelection )
showDefinition( selectedText, getGroup( ui.definition->url() ), getCurrentArticle() );
showDefinition( text, getGroup( ui.definition->url() ), getCurrentArticle() );
else if( result == saveBookmark )
{
emit saveBookmarkSignal( text.left( 60 ) );
}
else if( result == sendToAnkiAction )
{
sendToAnki( ui.definition->title(), ui.definition->selectedText() );
}
else
if ( result == lookupSelectionGr && groupComboBox )
showDefinition( selectedText, groupComboBox->getCurrentGroup(), QString() );
@ -2339,42 +2355,44 @@ void ArticleView::performFindOperation( bool restart, bool backwards, bool check
if ( backwards )
f |= QWebEnginePage::FindBackward;
bool setMark = text.size() && !findText(text, f);
findText( text,
f,
[ &text, this ]( bool match )
{
bool setMark = !text.isEmpty() && !match;
if ( ui.searchText->property( "noResults" ).toBool() != setMark )
{
ui.searchText->setProperty( "noResults", setMark );
if( ui.searchText->property( "noResults" ).toBool() != setMark )
{
ui.searchText->setProperty( "noResults", setMark );
// Reload stylesheet
reloadStyleSheet();
}
// Reload stylesheet
reloadStyleSheet();
}
} );
}
bool ArticleView::findText(QString& text, const QWebEnginePage::FindFlags& f)
void ArticleView::findText( QString & text,
const QWebEnginePage::FindFlags & f,
const std::function< void( bool match ) > & callback )
{
bool r;
// turn async to sync invoke.
QSharedPointer<QEventLoop> loop = QSharedPointer<QEventLoop>(new QEventLoop());
QTimer::singleShot(1000, loop.data(), &QEventLoop::quit);
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
ui.definition->findText(text, f, [&](const QWebEngineFindTextResult& result)
#if( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
ui.definition->findText( text,
f,
[ callback ]( const QWebEngineFindTextResult & result )
{
if(loop->isRunning()){
r = result.numberOfMatches()>0;
loop->quit();
} });
auto r = result.numberOfMatches() > 0;
if( callback )
callback( r );
} );
#else
ui.definition->findText(text, f, [&](bool result)
ui.definition->findText( text,
f,
[ callback ]( bool result )
{
if(loop->isRunning()){
r = result;
loop->quit();
} });
if( callback )
callback( result );
} );
#endif
loop->exec();
return r;
}
void ArticleView::reloadStyleSheet()
@ -2440,25 +2458,12 @@ void ArticleView::showEvent( QShowEvent * ev )
void ArticleView::receiveExpandOptionalParts( bool expand )
{
if( expandOptionalParts != expand )
{
int n = getArticlesList().indexOf( getActiveArticleId() );
if( n > 0 )
articleToJump = getCurrentArticle();
emit setExpandMode( expand );
expandOptionalParts = expand;
reload();
}
switchExpandOptionalParts();
}
void ArticleView::switchExpandOptionalParts()
{
expandOptionalParts = !expandOptionalParts;
int n = getArticlesList().indexOf( getActiveArticleId() );
if( n > 0 )
articleToJump = getCurrentArticle();
emit setExpandMode( expandOptionalParts );
reload();
}
@ -2498,6 +2503,12 @@ void ArticleView::highlightFTSResults()
else
regString = regString.remove( AccentMarkHandler::accentMark() );
//<div><i>watch</i>out</div> to plainText will return "watchout".
//if application goes here,that means the article text must contains the search text.
//whole word match regString will contain \b . can not match the above senario.
//workaround ,remove \b from the regstring="(\bwatch\b)"
regString.remove( QRegularExpression( "\\\\b" ) );
QRegularExpression regexp;
if( Utils::Url::hasQueryItem( url, "wildcards" ) )
regexp.setPattern( wildcardsToRegexp( regString ) );
@ -2548,17 +2559,15 @@ void ArticleView::highlightFTSResults()
if( ftsSearchMatchCase )
flags |= QWebEnginePage::FindCaseSensitively;
for( int x = 0; x < allMatches.size(); x++ )
ui.definition->findText( allMatches.at( x ), flags );
if( !allMatches.isEmpty() )
{
// highlightAllFtsOccurences( flags );
ui.definition->findText( allMatches.at( 0 ), flags );
// if( ui.definition->findText( allMatches.at( 0 ), flags ) )
{
ui.definition->page()->runJavaScript(
QString( "%1=window.getSelection().getRangeAt(0);_=0;" ).arg( rangeVarName ) );
}
// {
// ui.definition->page()->runJavaScript(
// QString( "%1=window.getSelection().getRangeAt(0);_=0;" ).arg( rangeVarName ) );
// }
}
ui.ftsSearchFrame->show();
@ -2569,6 +2578,25 @@ void ArticleView::highlightFTSResults()
} );
}
void ArticleView::highlightAllFtsOccurences( QWebEnginePage::FindFlags flags )
{
// Usually allMatches contains mostly duplicates. Thus searching for each element of
// allMatches to highlight them takes a long time => collect unique elements into a
// set and search for them instead.
// Don't use QList::toSet() or QSet's range constructor because they reserve space
// for QList::size() elements, whereas the final QSet size is likely 1 or 2.
QSet< QString > uniqueMatches;
for( int x = 0; x < allMatches.size(); ++x )
{
QString const & match = allMatches.at( x );
// Consider words that differ only in case equal if the search is case-insensitive.
uniqueMatches.insert( ftsSearchMatchCase ? match : match.toLower() );
}
for( QSet< QString >::const_iterator it = uniqueMatches.constBegin(); it != uniqueMatches.constEnd(); ++it )
ui.definition->findText( *it, flags );
}
void ArticleView::setActiveDictIds(ActiveDictIds ad) {
// ignore all other signals.
qDebug() << "receive dicts, current word:" << currentWord << ad.word << ":" << ad.dictIds;
@ -2651,9 +2679,9 @@ void ArticleView::performFtsFindOperation( bool backwards )
}
#endif
// Store new highlighted selection
ui.definition->page()->
runJavaScript( QString( "%1=window.getSelection().getRangeAt(0);_=0;" )
.arg( rangeVarName ) );
// ui.definition->page()->
// runJavaScript( QString( "%1=window.getSelection().getRangeAt(0);_=0;" )
// .arg( rangeVarName ) );
}
void ArticleView::on_ftsSearchPrevious_clicked()

View file

@ -19,6 +19,7 @@
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtCore5Compat/QRegExp>
#endif
#include "ankiconnector.h"
class ResourceToSaveHandler;
class ArticleViewAgent ;
@ -39,13 +40,14 @@ class ArticleView: public QFrame
ArticleViewAgent * agent;
Ui::ArticleView ui;
AnkiConnector * ankiConnector;
QAction pasteAction, articleUpAction, articleDownAction,
goBackAction, goForwardAction, selectCurrentArticleAction,
copyAsTextAction, inspectAction;
QAction & openSearchAction;
bool searchIsOpened;
bool expandOptionalParts;
QString articleToJump;
QString rangeVarName;
/// Any resource we've decided to download off the dictionary gets stored here.
@ -76,9 +78,11 @@ class ArticleView: public QFrame
bool ftsSearchIsOpened, ftsSearchMatchCase;
int ftsPosition;
QString delayedHighlightText;
void highlightFTSResults();
void highlightAllFtsOccurences( QWebEnginePage::FindFlags flags );
void performFtsFindOperation( bool backwards );
void showFindButtons();
public:
/// The popupView flag influences contents of the context menus to be
@ -129,6 +133,7 @@ public:
QRegExp const & searchRegExp, unsigned group,
bool ignoreDiacritics );
void sendToAnki(QString const & word, QString const & text );
/// Clears the view and sets the application-global waiting cursor,
/// which will be restored when some article loads eventually.
void showAnticipation();
@ -153,6 +158,8 @@ public:
/// Called when preference changes
void setSelectionBySingleClick( bool set );
void setDelayedHighlightText(QString const & text);
public slots:
/// Goes back in history
@ -168,8 +175,7 @@ public slots:
public:
/// Reloads the view
void reload()
{ ui.definition->reload(); }
void reload();
/// Returns true if there's an audio reference on the page, false otherwise.
void hasSound( const std::function< void( bool has ) > & callback );
@ -223,6 +229,10 @@ public:
ResourceToSaveHandler * saveResource( const QUrl & url, const QString & fileName );
ResourceToSaveHandler * saveResource( const QUrl & url, const QUrl & ref, const QString & fileName );
void findText( QString & text,
const QWebEnginePage::FindFlags & f,
const std::function< void( bool match ) > & callback = nullptr );
signals:
void iconChanged( ArticleView *, QIcon const & icon );
@ -281,6 +291,8 @@ signals:
void inspectSignal(QWebEngineView * view);
void saveBookmarkSignal( const QString & bookmark );
public slots:
void on_searchPrevious_clicked();
@ -360,7 +372,8 @@ private:
/// Sets the current article by executing a javascript code.
/// If moveToIt is true, it moves the focus to it as well.
void setCurrentArticle( QString const &, bool moveToIt = false );
/// Returns true in case of success, false otherwise.
bool setCurrentArticle( QString const &, bool moveToIt = false );
/// Checks if the given article in form of "gdfrom-xxx" is inside a "website"
/// frame.
@ -375,14 +388,13 @@ private:
/// url to the appropriate "contexts" entry.
void tryMangleWebsiteClickedUrl( QUrl & url, Contexts & contexts );
/// Use the known information about the current frame to update the current
/// article's value.
void updateCurrentArticleFromCurrentFrame( QWebEnginePage * frame = 0 ,QPoint * point=0);
/// Saves current article and scroll position for the current history item.
/// Should be used when leaving the page.
void saveHistoryUserData();
/// Loads a page at @p url into view.
void load( QUrl const & url );
/// Attempts removing last temporary file created.
void cleanupTemp();
@ -390,7 +402,6 @@ private:
void performFindOperation( bool restart, bool backwards, bool checkHighlight = false );
bool findText(QString& text, const QWebEnginePage::FindFlags& f);
void reloadStyleSheet();

View file

@ -1,15 +1,38 @@
#include "articlewebpage.h"
#include "utils.hh"
ArticleWebPage::ArticleWebPage(QObject *parent)
: QWebEnginePage{parent}
{
}
bool ArticleWebPage::acceptNavigationRequest( const QUrl & url, NavigationType type, bool isMainFrame )
bool ArticleWebPage::acceptNavigationRequest( const QUrl & resUrl, NavigationType type, bool isMainFrame )
{
QUrl url = resUrl;
if( url.scheme() == "bword" || url.scheme() == "entry" )
{
url.setScheme( "gdlookup" );
url.setHost( "localhost" );
url.setPath( "" );
auto [ valid, word ] = Utils::Url::getQueryWord( resUrl );
Utils::Url::addQueryItem( url, "word", word );
Utils::Url::addQueryItem( url, "group", lastReq.group );
Utils::Url::addQueryItem( url, "muted", lastReq.mutedDicts );
setUrl( url );
return false;
}
//save current gdlookup's values.
if( url.scheme() == "gdlookup" )
{
lastReq.group = Utils::Url::queryItemValue( url, "group" );
lastReq.mutedDicts = Utils::Url::queryItemValue( url, "muted" );
}
if( type == QWebEnginePage::NavigationTypeLinkClicked )
{
emit linkClicked( url );
return true;
}
return QWebEnginePage::acceptNavigationRequest( url, type, isMainFrame );
}

View file

@ -3,6 +3,11 @@
#include <QWebEnginePage>
struct LastReqInfo{
QString group;
QString mutedDicts;
};
class ArticleWebPage : public QWebEnginePage
{
Q_OBJECT
@ -12,6 +17,8 @@ signals:
void linkClicked( const QUrl & url );
protected:
virtual bool acceptNavigationRequest( const QUrl & url, NavigationType type, bool isMainFrame );
private:
LastReqInfo lastReq;
};
#endif // ARTICLEWEBPAGE_H

58
base/globalregex.cc Normal file
View file

@ -0,0 +1,58 @@
#include "globalregex.hh"
#include "fulltextsearch.hh"
using namespace RX;
QRegularExpression Ftx::regBrackets(
"(\\([\\w\\p{M}]+\\)){0,1}([\\w\\p{M}]+)(\\([\\w\\p{M}]+\\)){0,1}([\\w\\p{M}]+){0,1}(\\([\\w\\p{M}]+\\)){0,1}",
QRegularExpression::UseUnicodePropertiesOption );
QRegularExpression Ftx::regSplit( "[^\\w\\p{M}]+", QRegularExpression::UseUnicodePropertiesOption );
QRegularExpression Ftx::spacesRegExp( "\\W+", QRegularExpression::UseUnicodePropertiesOption );
QRegularExpression Ftx::wordRegExp( QString( "\\w{" ) + QString::number( FTS::MinimumWordSize ) + ",}",
QRegularExpression::UseUnicodePropertiesOption );
QRegularExpression Ftx::setsRegExp( "\\[[^\\]]+\\]", QRegularExpression::CaseInsensitiveOption );
QRegularExpression Ftx::regexRegExp( "\\\\[afnrtvdDwWsSbB]|\\\\x([0-9A-Fa-f]{4})|\\\\0([0-7]{3})",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Ftx::handleRoundBracket( "[^\\w\\(\\)\\p{M}]+" ,
QRegularExpression::UseUnicodePropertiesOption );
QRegularExpression Ftx::noRoundBracket( "[^\\w\\p{M}]+",
QRegularExpression::UseUnicodePropertiesOption );
//mdx
QRegularExpression Mdx::allLinksRe( "(?:<\\s*(a(?:rea)?|img|link|script|source)(?:\\s+[^>]+|\\s*)>)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::wordCrossLink( "([\\s\"']href\\s*=)\\s*([\"'])entry://([^>#]*?)((?:#[^>]*?)?)\\2",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::anchorIdRe( "([\\s\"'](?:name|id)\\s*=)\\s*([\"'])\\s*(?=\\S)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::anchorIdReWord( "([\\s\"'](?:name|id)\\s*=)\\s*([\"'])\\s*(?=\\S)([^\"]*)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::anchorIdRe2( "([\\s\"'](?:name|id)\\s*=)\\s*(?=[^\"'])([^\\s\">]+)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::anchorLinkRe( "([\\s\"']href\\s*=\\s*[\"'])entry://#",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::audioRe( "([\\s\"']href\\s*=)\\s*([\"'])sound://([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption
| QRegularExpression::InvertedGreedinessOption );
QRegularExpression Mdx::stylesRe( "([\\s\"']href\\s*=)\\s*([\"'])(?!\\s*\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::stylesRe2( "([\\s\"']href\\s*=)\\s*(?![\\s\"']|\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\\s\">]+)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::inlineScriptRe( "<\\s*script(?:(?=\\s)(?:(?![\\s\"']src\\s*=)[^>])+|\\s*)>",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::closeScriptTagRe( "<\\s*/script\\s*>", QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::srcRe( "([\\s\"']src\\s*=)\\s*([\"'])(?!\\s*\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::srcRe2( "([\\s\"']src\\s*=)\\s*(?![\\s\"']|\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\\s\">]+)",
QRegularExpression::CaseInsensitiveOption );
QRegularExpression Mdx::links( "url\\(\\s*(['\"]?)([^'\"]*)(['\"]?)\\s*\\)",
QRegularExpression::CaseInsensitiveOption );

44
base/globalregex.hh Normal file
View file

@ -0,0 +1,44 @@
#ifndef GLOBALREGEX_HH
#define GLOBALREGEX_HH
#include <QRegularExpression>
namespace RX
{
class Ftx
{
public:
static QRegularExpression regBrackets;
static QRegularExpression regSplit;
static QRegularExpression spacesRegExp;
static QRegularExpression wordRegExp;
static QRegularExpression setsRegExp;
static QRegularExpression regexRegExp;
static QRegularExpression handleRoundBracket;
static QRegularExpression noRoundBracket;
};
class Mdx
{
public:
static QRegularExpression allLinksRe;
static QRegularExpression wordCrossLink;
static QRegularExpression anchorIdRe;
static QRegularExpression anchorIdReWord;
static QRegularExpression anchorIdRe2;
static QRegularExpression anchorLinkRe;
static QRegularExpression audioRe;
static QRegularExpression stylesRe;
static QRegularExpression stylesRe2;
static QRegularExpression inlineScriptRe;
static QRegularExpression closeScriptTagRe;
static QRegularExpression srcRe;
static QRegularExpression srcRe2;
static QRegularExpression links;
};
} // namespace RX
#endif // GLOBALREGEX_HH

12
bgl.cc
View file

@ -198,16 +198,16 @@ namespace
BglDictionary( string const & id, string const & indexFile,
string const & dictionaryFile );
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -249,7 +249,7 @@ namespace
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -302,7 +302,7 @@ namespace
FTS_index_completed.ref();
}
void BglDictionary::loadIcon() throw()
void BglDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -1399,15 +1399,18 @@ void BtreeIndex::getHeadwordsFromOffsets( QList<uint32_t> & offsets,
for( unsigned i = 0; i < result.size(); i++ )
{
uint32_t articleOffset = result.at(i).articleOffset;
QList<uint32_t>::Iterator it = std::lower_bound( begOffsets, endOffsets,
articleOffset );
if( it!=offsets.end())
if( it != offsets.end() && *it == articleOffset )
{
if( isCancelled && Utils::AtomicInt::loadAcquire( *isCancelled ) )
return;
headwords.append( QString::fromUtf8( ( result[ i ].prefix + result[ i ].word ).c_str() ) );
auto word = QString::fromUtf8( ( result[ i ].prefix + result[ i ].word ).c_str() );
headwords.append( word );
offsets.erase( it);
begOffsets = offsets.begin();
endOffsets = offsets.end();

View file

@ -155,7 +155,7 @@ public:
BtreeDictionary( string const & id, vector< string > const & dictionaryFiles );
/// Btree-indexed dictionaries are usually a good source for compound searches.
virtual Dictionary::Features getFeatures() const throw()
virtual Dictionary::Features getFeatures() const noexcept
{ return Dictionary::SuitableForCompoundSearching; }
/// This function does the search using the btree index. Derivatives usually

View file

@ -31,7 +31,7 @@ public:
~CharacterConversionDictionary();
std::vector< gd::wstring > getAlternateWritings( gd::wstring const & )
throw();
noexcept;
};
CharacterConversionDictionary::CharacterConversionDictionary( std::string const & id,
@ -70,7 +70,7 @@ CharacterConversionDictionary::~CharacterConversionDictionary()
}
std::vector< gd::wstring > CharacterConversionDictionary::getAlternateWritings( gd::wstring const & str )
throw()
noexcept
{
std::vector< gd::wstring > results;

View file

@ -4,6 +4,8 @@
#include "chunkedstorage.hh"
#include <zlib.h>
#include <string.h>
#include <QDataStream>
#include <QScopeGuard>
namespace ChunkedStorage {
@ -134,25 +136,42 @@ char * Reader::getBlock( uint32_t address, vector< char > & chunk )
// Read and decompress the chunk
{
file.seek( offsets[ chunkIdx ] );
// file.seek( offsets[ chunkIdx ] );
QMutexLocker _( &file.lock );
auto bytes = file.map( offsets[ chunkIdx ], 8 );
if( bytes == nullptr )
throw mapFailed();
auto qBytes = QByteArray::fromRawData( reinterpret_cast< char * >(bytes), 8 );
QDataStream in( qBytes );
in.setByteOrder( QDataStream::LittleEndian );
uint32_t uncompressedSize = file.read< uint32_t >();
uint32_t compressedSize = file.read< uint32_t >();
uint32_t uncompressedSize;
uint32_t compressedSize;
in >> uncompressedSize >> compressedSize;
file.unmap( bytes );
chunk.resize( uncompressedSize );
vector< unsigned char > compressedData( compressedSize );
file.read( &compressedData.front(), compressedData.size() );
// vector< unsigned char > compressedData( compressedSize );
auto chunkDataBytes = file.map( offsets[ chunkIdx ] + 8, compressedSize );
if( chunkDataBytes == nullptr )
throw mapFailed();
// file.read( &compressedData.front(), compressedData.size() );
auto autoUnmap = qScopeGuard(
[ & ] {
file.unmap( chunkDataBytes );
} );
Q_UNUSED( autoUnmap )
unsigned long decompressedLength = chunk.size();
if ( uncompress( (unsigned char *)&chunk.front(),
&decompressedLength,
&compressedData.front(),
compressedData.size() ) != Z_OK ||
decompressedLength != chunk.size() )
if( uncompress( (unsigned char *)&chunk.front(), &decompressedLength, chunkDataBytes, compressedSize ) != Z_OK
|| decompressedLength != chunk.size() )
{
throw exFailedToDecompressChunk();
}
}
size_t offsetInChunk = address & 0xffFF;

View file

@ -25,6 +25,7 @@ DEF_EX( Ex, "Chunked storage exception", std::exception )
DEF_EX( exFailedToCompressChunk, "Failed to compress a chunk", Ex )
DEF_EX( exAddressOutOfRange, "The given chunked address is out of range", Ex )
DEF_EX( exFailedToDecompressChunk, "Failed to decompress a chunk", Ex )
DEF_EX( mapFailed, "Failed to map/unmap the file", Ex )
/// This class writes data blocks in chunks.
class Writer

View file

@ -89,6 +89,10 @@ ProxyServer::ProxyServer(): enabled( false ), useSystemProxy( false ), type( Soc
{
}
AnkiConnectServer::AnkiConnectServer(): enabled( false ), host("127.0.0.1"), port( 8765 )
{
}
HotKey::HotKey(): modifiers( 0 ), key1( 0 ), key2( 0 )
{
}
@ -937,6 +941,17 @@ Class load()
c.preferences.proxyServer.systemProxyPassword = proxy.namedItem( "systemProxyPassword" ).toElement().text();
}
QDomNode ankiConnectServer = preferences.namedItem( "ankiConnectServer" );
if ( !ankiConnectServer.isNull() )
{
c.preferences.ankiConnectServer.enabled = ( ankiConnectServer.toElement().attribute( "enabled" ) == "1" );
c.preferences.ankiConnectServer.host = ankiConnectServer.namedItem( "host" ).toElement().text();
c.preferences.ankiConnectServer.port = ankiConnectServer.namedItem( "port" ).toElement().text().toULong();
c.preferences.ankiConnectServer.deck = ankiConnectServer.namedItem( "deck" ).toElement().text();
c.preferences.ankiConnectServer.model = ankiConnectServer.namedItem( "model" ).toElement().text();
}
if ( !preferences.namedItem( "checkForNewReleases" ).isNull() )
c.preferences.checkForNewReleases = ( preferences.namedItem( "checkForNewReleases" ).toElement().text() == "1" );
@ -1872,6 +1887,32 @@ void save( Class const & c )
proxy.appendChild( opt );
}
//anki connect
{
QDomElement proxy = dd.createElement( "ankiConnectServer" );
preferences.appendChild( proxy );
QDomAttr enabled = dd.createAttribute( "enabled" );
enabled.setValue( c.preferences.ankiConnectServer.enabled ? "1" : "0" );
proxy.setAttributeNode( enabled );
opt = dd.createElement( "host" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.host ) );
proxy.appendChild( opt );
opt = dd.createElement( "port" );
opt.appendChild( dd.createTextNode( QString::number( c.preferences.ankiConnectServer.port ) ) );
proxy.appendChild( opt );
opt = dd.createElement( "deck" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.deck ) );
proxy.appendChild( opt );
opt = dd.createElement( "model" );
opt.appendChild( dd.createTextNode( c.preferences.ankiConnectServer.model ) );
proxy.appendChild( opt );
}
opt = dd.createElement( "checkForNewReleases" );
opt.appendChild( dd.createTextNode( c.preferences.checkForNewReleases ? "1" : "0" ) );
preferences.appendChild( opt );
@ -2211,7 +2252,7 @@ QString getUserQtCssFileName()
return getHomeDir().filePath( "qt-style.css" );
}
QString getProgramDataDir() throw()
QString getProgramDataDir() noexcept
{
if ( isPortableVersion() )
return QCoreApplication::applicationDirPath();
@ -2223,12 +2264,12 @@ QString getProgramDataDir() throw()
#endif
}
QString getEmbedLocDir() throw()
QString getEmbedLocDir() noexcept
{
return ":/locale";
}
QString getLocDir() throw()
QString getLocDir() noexcept
{
if ( QDir( getProgramDataDir() ).cd( "locale" ) )
return getProgramDataDir() + "/locale";
@ -2236,7 +2277,7 @@ QString getLocDir() throw()
return QCoreApplication::applicationDirPath() + "/locale";
}
QString getHelpDir() throw()
QString getHelpDir() noexcept
{
if ( QDir( getProgramDataDir() ).cd( "help" ) )
return getProgramDataDir() + "/help";
@ -2245,7 +2286,7 @@ QString getHelpDir() throw()
}
#ifdef MAKE_CHINESE_CONVERSION_SUPPORT
QString getOpenCCDir() throw()
QString getOpenCCDir() noexcept
{
#if defined( Q_OS_WIN )
if ( QDir( "opencc" ).exists() )
@ -2264,7 +2305,7 @@ QString getOpenCCDir() throw()
}
#endif
bool isPortableVersion() throw()
bool isPortableVersion() noexcept
{
struct IsPortable
{
@ -2279,7 +2320,7 @@ bool isPortableVersion() throw()
return p.isPortable;
}
QString getPortableVersionDictionaryDir() throw()
QString getPortableVersionDictionaryDir() noexcept
{
if ( isPortableVersion() )
return getProgramDataDir() + "/content";
@ -2287,7 +2328,7 @@ QString getPortableVersionDictionaryDir() throw()
return QString();
}
QString getPortableVersionMorphoDir() throw()
QString getPortableVersionMorphoDir() noexcept
{
if ( isPortableVersion() )
return getPortableVersionDictionaryDir() + "/morphology";
@ -2307,7 +2348,7 @@ QString getStylesDir()
return result.path() + QDir::separator();
}
QString getCacheDir() throw()
QString getCacheDir() noexcept
{
return isPortableVersion() ? portableHomeDirPath() + "/cache"
#ifdef HAVE_X11
@ -2317,7 +2358,7 @@ QString getCacheDir() throw()
#endif
}
QString getNetworkCacheDir() throw()
QString getNetworkCacheDir() noexcept
{
return getCacheDir() + "/network";
}

View file

@ -137,6 +137,18 @@ struct ProxyServer
ProxyServer();
};
struct AnkiConnectServer
{
bool enabled;
QString host;
unsigned port;
QString deck;
QString model;
AnkiConnectServer();
};
// A hotkey -- currently qt modifiers plus one or two keys
struct HotKey
{
@ -329,6 +341,7 @@ struct Preferences
QString audioPlaybackProgram;
ProxyServer proxyServer;
AnkiConnectServer ankiConnectServer;
bool checkForNewReleases;
bool disallowContentFromOtherSites;
@ -795,40 +808,40 @@ QString getUserQtCssFileName() ;
/// Returns the program's data dir. Under Linux that would be something like
/// /usr/share/apps/goldendict, under Windows C:/Program Files/GoldenDict.
QString getProgramDataDir() throw();
QString getProgramDataDir() noexcept;
/// Returns the directory storing program localizized files (.qm).
QString getEmbedLocDir() throw();
QString getLocDir() throw();
QString getEmbedLocDir() noexcept;
QString getLocDir() noexcept;
/// Returns the directory storing program help files (.qch).
QString getHelpDir() throw();
QString getHelpDir() noexcept;
#ifdef MAKE_CHINESE_CONVERSION_SUPPORT
/// Returns the directory storing OpenCC configuration and dictionary files (.json and .ocd).
QString getOpenCCDir() throw();
QString getOpenCCDir() noexcept;
#endif
/// Returns true if the program is configured as a portable version. In that
/// mode, all the settings and indices are kept in the program's directory.
bool isPortableVersion() throw();
bool isPortableVersion() noexcept;
/// Returns directory with dictionaries for portable version. It is content/
/// in the application's directory.
QString getPortableVersionDictionaryDir() throw();
QString getPortableVersionDictionaryDir() noexcept;
/// Returns directory with morpgologies for portable version. It is
/// content/morphology in the application's directory.
QString getPortableVersionMorphoDir() throw();
QString getPortableVersionMorphoDir() noexcept;
/// Returns the add-on styles directory.
QString getStylesDir();
/// Returns the directory where user-specific non-essential (cached) data should be written.
QString getCacheDir() throw();
QString getCacheDir() noexcept;
/// Returns the article network disk cache directory.
QString getNetworkCacheDir() throw();
QString getNetworkCacheDir() noexcept;
}

View file

@ -100,19 +100,19 @@ public:
~DictdDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
inline virtual quint32 getLangFrom() const
{ return idxHeader.langFrom; }
@ -215,7 +215,7 @@ string nameFromFileName( string const & indexFileName )
return Utf8::encode( FsEncoding::decode( string( sep + 1, dot - sep - 1 ) ) );
}
void DictdDictionary::loadIcon() throw()
void DictdDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -159,7 +159,7 @@ sptr< WordSearchRequest > Class::findHeadwordsForSynonym( wstring const & )
}
vector< wstring > Class::getAlternateWritings( wstring const & )
throw()
noexcept
{
return vector< wstring >();
}
@ -185,21 +185,21 @@ QString Class::getMainFilename()
return QString();
}
QIcon const & Class::getIcon() throw()
QIcon const & Class::getIcon() noexcept
{
if( !dictionaryIconLoaded )
loadIcon();
return dictionaryIcon;
}
QIcon const & Class::getNativeIcon() throw()
QIcon const & Class::getNativeIcon() noexcept
{
if( !dictionaryIconLoaded )
loadIcon();
return dictionaryNativeIcon;
}
void Class::loadIcon() throw()
void Class::loadIcon() noexcept
{
dictionaryIconLoaded = true;
}
@ -424,7 +424,7 @@ void Class::isolateCSS( QString & css, QString const & wrapperSelector )
css = newCSS;
}
string makeDictionaryId( vector< string > const & dictionaryFiles ) throw()
string makeDictionaryId( vector< string > const & dictionaryFiles ) noexcept
{
std::vector< string > sortedList;
@ -470,7 +470,7 @@ string makeDictionaryId( vector< string > const & dictionaryFiles ) throw()
// of a timestamp of the file, so we use here Qt anyway. It is supposed to
// be fixed in the future when it's needed.
bool needToRebuildIndex( vector< string > const & dictionaryFiles,
string const & indexFile ) throw()
string const & indexFile ) noexcept
{
unsigned long lastModified = 0;

View file

@ -270,7 +270,7 @@ protected:
// Load user icon if it exist
// By default set icon to empty
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
// Load icon from filename directly if isFullName == true
// else treat filename as name without extension
@ -295,39 +295,39 @@ public:
virtual void deferredInit();
/// Returns the dictionary's id.
string getId() throw()
string getId() noexcept
{ return id; }
/// Returns the list of file names the dictionary consists of.
vector< string > const & getDictionaryFilenames() throw()
vector< string > const & getDictionaryFilenames() noexcept
{ return dictionaryFiles; }
/// Returns the dictionary's full name, utf8.
virtual string getName() throw()=0;
virtual string getName() noexcept=0;
/// Returns all the available properties, like the author's name, copyright,
/// description etc. All strings are in utf8.
virtual map< Property, string > getProperties() throw()=0;
virtual map< Property, string > getProperties() noexcept=0;
/// Returns the features the dictionary possess. See the Feature enum for
/// their list.
virtual Features getFeatures() const throw()
virtual Features getFeatures() const noexcept
{ return NoFeatures; }
/// Returns the number of articles in the dictionary.
virtual unsigned long getArticleCount() throw()=0;
virtual unsigned long getArticleCount() noexcept=0;
/// Returns the number of words in the dictionary. This can be equal to
/// the number of articles, or can be larger if some synonyms are present.
virtual unsigned long getWordCount() throw()=0;
virtual unsigned long getWordCount() noexcept=0;
/// Returns the dictionary's icon.
virtual QIcon const & getIcon() throw();
virtual QIcon const & getIcon() noexcept;
/// Returns the dictionary's native icon. Dsl icons are usually rectangular,
/// and are adapted by getIcon() to be square. This function allows getting
/// the original icon with no geometry transformations applied.
virtual QIcon const & getNativeIcon() throw();
virtual QIcon const & getNativeIcon() noexcept;
/// Returns the dictionary's source language.
virtual quint32 getLangFrom() const
@ -371,7 +371,7 @@ public:
/// supposed to be very fast and simple, and the results are thus returned
/// synchronously.
virtual vector< wstring > getAlternateWritings( wstring const & )
throw();
noexcept;
/// Returns a definition for the given word. The definition should
/// be an html fragment (without html/head/body tags) in an utf8 encoding.
@ -454,7 +454,7 @@ public:
/// dictionary is being indexed. Since indexing can take some time, this
/// is useful to show in some kind of a splash screen.
/// The dictionaryName is in utf8.
virtual void indexingDictionary( string const & dictionaryName ) throw()=0;
virtual void indexingDictionary( string const & dictionaryName ) noexcept=0;
virtual ~Initializing()
{}
@ -465,7 +465,7 @@ public:
/// hashing the file names. This id should be used to identify dictionary
/// and for the index file name, if one is needed.
/// This function is supposed to be used by dictionary implementations.
string makeDictionaryId( vector< string > const & dictionaryFiles ) throw();
string makeDictionaryId( vector< string > const & dictionaryFiles ) noexcept;
/// Checks if it is needed to regenerate index file based on its timestamp
/// and the timestamps of the dictionary files. If some files are newer than
@ -473,7 +473,7 @@ string makeDictionaryId( vector< string > const & dictionaryFiles ) throw();
/// dictionary files don't exist, returns true, too.
/// This function is supposed to be used by dictionary implementations.
bool needToRebuildIndex( vector< string > const & dictionaryFiles,
string const & indexFile ) throw();
string const & indexFile ) noexcept;
/// Returns a random dictionary id useful for interactively created
/// dictionaries.

View file

@ -209,16 +209,16 @@ public:
strategies.append( "prefix" );
}
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const &,
@ -237,7 +237,7 @@ public:
virtual QString const & getDescription();
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
void getServerDatabases();
@ -245,7 +245,7 @@ protected:
friend class DictServerArticleRequest;
};
void DictServerDictionary::loadIcon() throw()
void DictServerDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

97
dsl.cc
View file

@ -128,11 +128,7 @@ struct InsidedCard
InsidedCard( uint32_t _offset, uint32_t _size, QVector< wstring > const & words ) :
offset( _offset ), size( _size ), headwords( words )
{}
InsidedCard( InsidedCard const & e ) :
offset( e.offset ), size( e.size ), headwords( e.headwords )
{}
InsidedCard() {}
};
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
@ -187,16 +183,16 @@ public:
~DslDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -251,7 +247,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -470,7 +466,7 @@ void DslDictionary::doDeferredInit()
}
void DslDictionary::loadIcon() throw()
void DslDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -1556,32 +1552,8 @@ void DslDictionary::getArticleText( uint32_t articleAddress, QString & headword,
/// DslDictionary::getArticle()
class DslArticleRequest;
class DslArticleRequestRunnable: public QRunnable
{
DslArticleRequest & r;
QSemaphore & hasExited;
public:
DslArticleRequestRunnable( DslArticleRequest & r_,
QSemaphore & hasExited_ ): r( r_ ),
hasExited( hasExited_ )
{}
~DslArticleRequestRunnable()
{
hasExited.release();
}
virtual void run();
};
class DslArticleRequest: public Dictionary::DataRequest
{
friend class DslArticleRequestRunnable;
wstring word;
vector< wstring > alts;
DslDictionary & dict;
@ -1597,11 +1569,10 @@ public:
DslDictionary & dict_, bool ignoreDiacritics_ ):
word( word_ ), alts( alts_ ), dict( dict_ ), ignoreDiacritics( ignoreDiacritics_ )
{
QThreadPool::globalInstance()->start(
new DslArticleRequestRunnable( *this, hasExited ) );
QThreadPool::globalInstance()->start( [ this ]() { this->run(); } );
}
void run(); // Run from another thread by DslArticleRequestRunnable
void run();
virtual void cancel()
{
@ -1611,15 +1582,10 @@ public:
~DslArticleRequest()
{
isCancelled.ref();
hasExited.acquire();
//hasExited.acquire();
}
};
void DslArticleRequestRunnable::run()
{
r.run();
}
void DslArticleRequest::run()
{
if ( Utils::AtomicInt::loadAcquire( isCancelled ) )
@ -1731,7 +1697,7 @@ void DslArticleRequest::run()
{
gdWarning( "DSL: Failed loading article from \"%s\", reason: %s\n", dict.getName().c_str(), ex.what() );
articleText = string( "<span class=\"dsl_article\">" )
+ string( QObject::tr( "Article loading error" ).toUtf8().constData() )
+ QObject::tr( "Article loading error" ).toStdString()
+ "</span>";
}
@ -1759,32 +1725,8 @@ sptr< Dictionary::DataRequest > DslDictionary::getArticle( wstring const & word,
//// DslDictionary::getResource()
class DslResourceRequest;
class DslResourceRequestRunnable: public QRunnable
{
DslResourceRequest & r;
QSemaphore & hasExited;
public:
DslResourceRequestRunnable( DslResourceRequest & r_,
QSemaphore & hasExited_ ): r( r_ ),
hasExited( hasExited_ )
{}
~DslResourceRequestRunnable()
{
hasExited.release();
}
virtual void run();
};
class DslResourceRequest: public Dictionary::DataRequest
{
friend class DslResourceRequestRunnable;
DslDictionary & dict;
string resourceName;
@ -1799,11 +1741,10 @@ public:
dict( dict_ ),
resourceName( resourceName_ )
{
QThreadPool::globalInstance()->start(
new DslResourceRequestRunnable( *this, hasExited ) );
QThreadPool::globalInstance()->start( [ this ]() { this->run(); } );
}
void run(); // Run from another thread by DslResourceRequestRunnable
void run();
virtual void cancel()
{
@ -1813,15 +1754,10 @@ public:
~DslResourceRequest()
{
isCancelled.ref();
hasExited.acquire();
//hasExited.acquire();
}
};
void DslResourceRequestRunnable::run()
{
r.run();
}
void DslResourceRequest::run()
{
// Some runnables linger enough that they are cancelled before they start
@ -2153,10 +2089,9 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
hasString = false;
// The line read should either consist of pure whitespace, or be a
// headword
if ( curString.empty() )
// The line read should either consist of pure whitespace, or be a headword
// skip too long headword,it can never be headword.
if( curString.empty() || curString.size() > 100 )
continue;
if ( isDslWs( curString[ 0 ] ) )

View file

@ -983,7 +983,7 @@ DslScanner::DslScanner( string const & fileName ) :
readBufferLeft = 0;
}
DslScanner::~DslScanner() throw()
DslScanner::~DslScanner() noexcept
{
gzclose( f );
}
@ -1155,12 +1155,6 @@ void expandOptionalParts( wstring & str, list< wstring > * result,
list< wstring > * headwords;
headwords = inside_recurse ? result : &expanded;
//if str is too long ,it can never be headwords.
//todo?
if( str.size() > 100 )
{
return;
}
for( ; x < str.size(); )
{
wchar ch = str[ x ];

View file

@ -113,7 +113,6 @@ class DslScanner
wstring langFrom, langTo;
wstring soundDictionary;
char readBuffer[ 65536 ];
QTextStream* fragStream;
char * readBufferPtr;
LineFeed lineFeed;
size_t readBufferLeft;
@ -130,7 +129,7 @@ public:
DEF_EX( exEncodingError, "Encoding error", Ex ) // Should never happen really
DslScanner( string const & fileName ) ;
~DslScanner() throw();
~DslScanner() noexcept;
/// Returns the detected encoding of this file.
Encoding getEncoding() const

View file

@ -44,7 +44,7 @@ namespace {
enum
{
Signature = 0x58575045, // EPWX on little-endian, XWPE on big-endian
CurrentFormatVersion = 5 + BtreeIndexing::FormatVersion + Folding::Version
CurrentFormatVersion = 6 + BtreeIndexing::FormatVersion + Folding::Version
};
struct IdxHeader
@ -96,16 +96,16 @@ public:
~EpwingDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return bookName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -163,7 +163,7 @@ public:
protected:
void loadIcon() throw();
void loadIcon() noexcept;
private:
@ -244,7 +244,7 @@ EpwingDictionary::~EpwingDictionary()
removeDirectory( cacheDirectory );
}
void EpwingDictionary::loadIcon() throw()
void EpwingDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -850,14 +850,14 @@ void EpwingBook::getFirstHeadword( EpwingHeadword & head )
fixHeadword( head.headword );
EWPos epos( pos.page, pos.offset );
allHeadwordPositions[ head.headword ] = epos;
allHeadwordPositions[ head.headword ] << epos;
}
bool EpwingBook::getNextHeadword( EpwingHeadword & head )
{
EB_Position pos;
QRegularExpression badLinks( "#(v|n)\\d" );
QRegularExpression badLinks( "#(v|n)\\d", QRegularExpression::UseUnicodePropertiesOption);
// At first we check references queue
while( !LinksQueue.isEmpty() )
@ -881,13 +881,25 @@ bool EpwingBook::getNextHeadword( EpwingHeadword & head )
if( allHeadwordPositions.contains( head.headword ) )
{
EWPos epos = allHeadwordPositions[ head.headword ];
if( pos.page != epos.first || abs( pos.offset - epos.second ) > 4 )
// existed position
bool existed = false;
foreach( EWPos epos, allHeadwordPositions[ head.headword ] )
{
if( pos.page == epos.first && abs( pos.offset - epos.second ) <= 4 )
{
existed = true;
break;
}
}
if( !existed )
{
allHeadwordPositions[ head.headword ] << EWPos( pos.page, pos.offset );
return true;
}
}
else
{
allHeadwordPositions[ head.headword ] = EWPos( pos.page, pos.offset );
allHeadwordPositions[ head.headword ] << EWPos( pos.page, pos.offset );
return true;
}
}
@ -943,14 +955,26 @@ bool EpwingBook::getNextHeadword( EpwingHeadword & head )
if( allHeadwordPositions.contains( head.headword ) )
{
EWPos epos = allHeadwordPositions[ head.headword ];
if( pos.page != epos.first || abs( pos.offset - epos.second ) > 4 )
break;
// existed position
bool existed = false;
foreach( EWPos epos, allHeadwordPositions[ head.headword ] )
{
if( pos.page == epos.first && abs( pos.offset - epos.second ) <= 4 )
{
existed = true;
break;
}
}
if( !existed )
{
allHeadwordPositions[ head.headword ] << EWPos( pos.page, pos.offset );
return true;
}
}
else
{
allHeadwordPositions[ head.headword ] = EWPos( pos.page, pos.offset );
break;
allHeadwordPositions[ head.headword ] << EWPos( pos.page, pos.offset );
return true;
}
}
@ -1104,6 +1128,9 @@ void EpwingBook::getArticle( QString & headword, QString & articleText,
headword = QString::fromUtf8( buffer, length );
finalizeText( headword );
if( text_only )
fixHeadword( headword );
articleText = getText( pos.page, pos.offset, text_only );
}

View file

@ -78,7 +78,7 @@ class EpwingBook
QStringList imageCacheList, soundsCacheList, moviesCacheList, fontsCacheList;
QMap< QString, QString > baseFontsMap, customFontsMap;
QVector< int > refPages, refOffsets;
QMap< QString, EWPos > allHeadwordPositions;
QMap< QString, QList< EWPos > > allHeadwordPositions;
QVector< EWPos > LinksQueue;
int refOpenCount, refCloseCount;
static Mutex libMutex;

8
ex.hh
View file

@ -14,8 +14,8 @@
#define DEF_EX( exName, exDescription, exParent ) \
class exName: public exParent { \
public: \
virtual const char * what() const throw() { return (exDescription); } \
virtual ~exName() throw() {} };
virtual const char * what() const noexcept { return (exDescription); } \
virtual ~exName() noexcept {} };
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
/// with the description.
@ -31,7 +31,7 @@ class exName: public exParent { \
std::string value; \
public: \
exName( std::string const & value_ ): value( std::string( exDescription ) + " " + value_ ) {} \
virtual const char * what() const throw() { return value.c_str(); } \
virtual ~exName() throw() {} };
virtual const char * what() const noexcept { return value.c_str(); } \
virtual ~exName() noexcept {} };
#endif

18
file.cc
View file

@ -65,7 +65,7 @@ void loadFromFile( std::string const & n, std::vector< char > & data )
f.read( &data.front(), data.size() );
}
bool exists( char const * filename ) throw()
bool exists( char const * filename ) noexcept
{
#ifdef __WIN32
#if defined(__WIN64) || defined(_MSC_VER)
@ -256,6 +256,20 @@ void Class::seek( qint64 offset )
throw exSeekError();
}
uchar * Class::map( qint64 offset, qint64 size )
{
if( writeBuffer )
flushWriteBuffer();
return f.map( offset, size );
}
bool Class::unmap( uchar * address )
{
return f.unmap( address );
}
void Class::seekCur( qint64 offset )
{
if ( writeBuffer )
@ -313,7 +327,7 @@ void Class::close()
f.close();
}
Class::~Class() throw()
Class::~Class() noexcept
{
if ( f.isOpen() )
{

10
file.hh
View file

@ -9,6 +9,7 @@
#include <vector>
#include <QFile>
#include "ex.hh"
#include "mutex.hh"
/// A simple wrapper over FILE * operations with added write-buffering,
/// used for non-Qt parts of code.
@ -30,9 +31,9 @@ bool tryPossibleZipName( std::string const & name, std::string & copyTo );
void loadFromFile( std::string const & n, std::vector< char > & data );
bool exists( char const * filename ) throw();
bool exists( char const * filename ) noexcept;
inline bool exists( std::string const & filename ) throw()
inline bool exists( std::string const & filename ) noexcept
{ return exists( filename.c_str() ); }
class Class
@ -44,6 +45,7 @@ class Class
void open( char const * filename, char const * mode ) ;
public:
QMutex lock;
Class( char const * filename, char const * mode ) ;
@ -95,6 +97,7 @@ public:
/// Seeks in the file, relative to its beginning.
void seek( qint64 offset ) ;
uchar * map( qint64 offset, qint64 size );
/// Seeks in the file, relative to the current position.
void seekCur( qint64 offset ) ;
/// Seeks in the file, relative to the end of file.
@ -116,7 +119,8 @@ public:
/// Closes the file. No further operations are valid.
void close() ;
~Class() throw();
~Class() noexcept;
bool unmap( uchar * address );
private:

View file

@ -42,16 +42,16 @@ public:
{
}
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const & /*word*/,
@ -70,7 +70,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
@ -90,7 +90,7 @@ sptr< DataRequest > ForvoDictionary::getArticle( wstring const & word,
netMgr );
}
void ForvoDictionary::loadIcon() throw()
void ForvoDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

File diff suppressed because it is too large Load diff

View file

@ -55,7 +55,8 @@ bool parseSearchString( QString const & str, QStringList & IndexWords,
QRegExp & searchRegExp, int searchMode,
bool matchCase,
int distanceBetweenWords,
bool & hasCJK );
bool & hasCJK,
bool ignoreWordsOrder = false );
void parseArticleForFts( uint32_t articleAddress, QString & articleText,
QMap< QString, QVector< uint32_t > > & words,
@ -65,28 +66,6 @@ void makeFTSIndex( BtreeIndexing::BtreeDictionary * dict, QAtomicInt & isCancell
bool isCJKChar( ushort ch );
class FTSResultsRequest;
class FTSResultsRequestRunnable : public QRunnable
{
FTSResultsRequest & r;
QSemaphore & hasExited;
public:
FTSResultsRequestRunnable( FTSResultsRequest & r_,
QSemaphore & hasExited_ ) : r( r_ ),
hasExited( hasExited_ )
{}
~FTSResultsRequestRunnable()
{
hasExited.release();
}
virtual void run();
};
class FTSResultsRequest : public Dictionary::DataRequest
{
BtreeIndexing::BtreeDictionary & dict;
@ -102,18 +81,24 @@ class FTSResultsRequest : public Dictionary::DataRequest
int wordsInIndex;
QAtomicInt isCancelled;
QSemaphore hasExited;
QAtomicInt results;
QList< FTS::FtsHeadword > * foundHeadwords;
void checkArticles( QVector< uint32_t > const & offsets,
QStringList const & words,
QRegExp const & searchRegexp = QRegExp() );
QRegularExpression createMatchRegex( QRegExp const & searchRegexp );
void checkSingleArticle( uint32_t offset,
QStringList const & words,
QRegularExpression const & searchRegexp = QRegularExpression() );
void indexSearch( BtreeIndexing::BtreeIndex & ftsIndex,
sptr< ChunkedStorage::Reader > chunks,
QStringList & indexWords,
QStringList & searchWords );
QStringList & searchWords, QRegExp & regexp );
void combinedIndexSearch( BtreeIndexing::BtreeIndex & ftsIndex,
sptr< ChunkedStorage::Reader > chunks,
@ -149,11 +134,11 @@ public:
searchString = gd::toQString( Folding::applyDiacriticsOnly( gd::toWString( searchString_ ) ) );
foundHeadwords = new QList< FTS::FtsHeadword >;
QThreadPool::globalInstance()->start(
new FTSResultsRequestRunnable( *this, hasExited ), -100 );
results = 0;
QThreadPool::globalInstance()->start( [ this ]() { this->run(); }, -100 );
}
void run(); // Run from another thread by DslResourceRequestRunnable
void run();
virtual void cancel()
{
@ -165,7 +150,6 @@ public:
isCancelled.ref();
if( foundHeadwords )
delete foundHeadwords;
hasExited.acquire();
}
};

View file

@ -351,27 +351,15 @@ void FullTextSearchDialog::accept()
searchRegExp, mode,
ui.matchCase->isChecked(),
distanceBetweenWords,
hasCJK ) )
hasCJK, ignoreWordsOrder ) )
{
if( hasCJK && ( mode == WholeWords || mode == PlainText ) )
{
QMessageBox message( QMessageBox::Warning,
"GoldenDict",
tr( "CJK symbols in search string are not compatible with search modes \"Whole words\" and \"Plain text\"" ),
QMessageBox::Ok,
this );
message.exec();
}
else
{
QMessageBox message( QMessageBox::Warning,
"GoldenDict",
tr( "The search line must contains at least one word containing " )
QMessageBox message( QMessageBox::Warning,
"GoldenDict",
tr( "The search line must contains at least one word containing " )
+ QString::number( MinimumWordSize ) + tr( " or more symbols" ),
QMessageBox::Ok,
this );
message.exec();
}
QMessageBox::Ok,
this );
message.exec();
return;
}
@ -393,6 +381,10 @@ void FullTextSearchDialog::accept()
for( unsigned x = 0; x < activeDicts.size(); ++x )
{
if( !activeDicts[ x ] ->haveFTSIndex())
{
continue;
}
sptr< Dictionary::DataRequest > req = activeDicts[ x ]->getSearchResults(
ui.searchLine->text(),
mode,
@ -621,7 +613,7 @@ Q_UNUSED( parent );
for( int x = 0; x < hws.length(); x++ )
{
QList< FtsHeadword >::iterator it = std::lower_bound( headwords.begin(), headwords.end(), hws.at( x ) );
if( it != headwords.end() )
if( it != headwords.end() && *it == hws.at( x ) )
{
it->dictIDs.push_back( hws.at( x ).dictIDs.front() );
for( QStringList::const_iterator itr = it->foundHiliteRegExps.constBegin();

View file

@ -4,61 +4,30 @@
#include <QString>
#include "gddebug.hh"
#include <QDebug>
#if(QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#if( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
#include <QtCore5Compat/QTextCodec>
#else
#include <QTextCodec>
#endif
QFile * logFilePtr;
static QTextCodec * utf8Codec;
void gdWarning(const char *msg, ...)
void gdWarning( const char * msg, ... )
{
va_list ap;
va_start(ap, msg);
QTextCodec *localeCodec = 0;
if( logFilePtr && logFilePtr->isOpen() )
{
if( utf8Codec == 0 )
utf8Codec = QTextCodec::codecForName( "UTF8" );
localeCodec = QTextCodec::codecForLocale();
QTextCodec::setCodecForLocale( utf8Codec );
}
va_list ap;
va_start( ap, msg );
qWarning() << QString().vasprintf( msg, ap );
if( logFilePtr && logFilePtr->isOpen() )
{
QTextCodec::setCodecForLocale( localeCodec );
}
va_end(ap);
va_end( ap );
}
void gdDebug(const char *msg, ...)
void gdDebug( const char * msg, ... )
{
va_list ap;
va_start(ap, msg);
// QTextCodec *localeCodec = 0;
// if( logFilePtr && logFilePtr->isOpen() )
// {
// if( utf8Codec == 0 )
// utf8Codec = QTextCodec::codecForName( "UTF8" );
// localeCodec = QTextCodec::codecForLocale();
// QTextCodec::setCodecForLocale( utf8Codec );
// }
va_list ap;
va_start( ap, msg );
qDebug().noquote() << QString().vasprintf( msg, ap );
// if( logFilePtr && logFilePtr->isOpen() )
// {
// QTextCodec::setCodecForLocale( localeCodec );
// }
va_end(ap);
va_end( ap );
}

View file

@ -20,13 +20,15 @@ Config::Preferences * GlobalBroadcaster::getPreference()
return preference;
}
void GlobalBroadcaster::addWhitelist(QString url){
whitelist.push_back(url);
auto baseUrl=::getHostBase(url);
whitelist.push_back(baseUrl);
void GlobalBroadcaster::addWhitelist( QString url )
{
whitelist.push_back( url );
auto baseUrl = ::getHostBase( url );
whitelist.push_back( baseUrl );
}
bool GlobalBroadcaster::existedInWhitelist(QString url){
return std::find(whitelist.begin(), whitelist.end(), url) != whitelist.end();
bool GlobalBroadcaster::existedInWhitelist( QString url )
{
return std::find( whitelist.begin(), whitelist.end(), url ) != whitelist.end();
}
// namespace global

View file

@ -17,6 +17,7 @@ class GlobalBroadcaster : public QObject
private:
Config::Preferences * preference;
std::vector<QString> whitelist;
public:
void setPreference( Config::Preferences * _pre );
Config::Preferences * getPreference();
@ -24,6 +25,7 @@ public:
void addWhitelist(QString host);
bool existedInWhitelist(QString host);
static GlobalBroadcaster * instance();
signals:
void dictionaryChanges( ActiveDictIds ad );
};

16
gls.cc
View file

@ -88,7 +88,7 @@ public:
DEF_EX( exEncodingError, "Encoding error", Ex ) // Should never happen really
GlsScanner( string const & fileName ) ;
~GlsScanner() throw();
~GlsScanner() noexcept;
/// Returns the detected encoding of this file.
Encoding getEncoding() const
@ -293,7 +293,7 @@ bool GlsScanner::readNextLine( wstring & out, size_t & offset )
}
}
GlsScanner::~GlsScanner() throw()
GlsScanner::~GlsScanner() noexcept
{
gzclose( f );
}
@ -372,16 +372,16 @@ public:
~GlsDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -425,7 +425,7 @@ public:
}
protected:
void loadIcon() throw();
void loadIcon() noexcept;
private:
@ -517,7 +517,7 @@ GlsDictionary::~GlsDictionary()
dict_data_close( dz );
}
void GlsDictionary::loadIcon() throw()
void GlsDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -12,7 +12,28 @@ system(git describe --tags --always --dirty): hasGit=1
!isEmpty(hasGit){
GIT_HASH=$$system(git rev-parse --short=8 HEAD )
}
system(echo $${VERSION}.$${GIT_HASH} > version.txt)
win32{
# date /T output is locale aware.
DATE=$$system(date /T)
}
else{
DATE=$$system(date '+%Y/%m/%d')
}
system(echo $${VERSION}.$${GIT_HASH} on $${DATE} > version.txt)
!CONFIG( verbose_build_output ) {
!win32|*-msvc* {
# Reduce build log verbosity except for MinGW builds (mingw-make cannot
# execute "@echo ..." commands inserted by qmake).
CONFIG += silent
}
}
CONFIG( release, debug|release ) {
DEFINES += NDEBUG
}
# DEPENDPATH += . generators
INCLUDEPATH += .
@ -26,7 +47,8 @@ QT += core \
webenginewidgets\
webchannel\
printsupport \
help
help \
concurrent
greaterThan(QT_MAJOR_VERSION, 5): QT += webenginecore core5compat
@ -42,11 +64,10 @@ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050F00
DEFINES += MAKE_FFMPEG_PLAYER
}
#QT += sql
CONFIG += exceptions \
rtti \
stl \
c++14 \
c++17 \
lrelease \
embed_translations
@ -66,6 +87,8 @@ LIBS += \
CONFIG+=utf8_source
CONFIG+=force_debug_info
win32 {
TARGET = GoldenDict
@ -76,13 +99,10 @@ win32 {
DEFINES += NOMINMAX __WIN64
}
LIBS += -L$${PWD}/winlibs/lib/msvc
QMAKE_CXXFLAGS += /wd4290 # silence the warning C4290: C++ exception specification ignored
# silence the warning C4290: C++ exception specification ignored
QMAKE_CXXFLAGS += /wd4290 /Zc:__cplusplus /std:c++17 /permissive-
# QMAKE_LFLAGS_RELEASE += /OPT:REF /OPT:ICF
# QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /DEBUG
CONFIG+=force_debug_info
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
DEFINES += GD_NO_MANIFEST
# QMAKE_CXXFLAGS_RELEASE += /GL # slows down the linking significantly
LIBS += -lshell32 -luser32 -lsapi -lole32
Debug: LIBS+= -lhunspelld
@ -126,7 +146,6 @@ unix:!mac {
DEFINES += HAVE_X11
lessThan(QT_MAJOR_VERSION, 6): QT += x11extras
greaterThan(QT_MAJOR_VERSION, 5): QT += gui-private
CONFIG += link_pkgconfig
@ -141,9 +160,7 @@ unix:!mac {
libavcodec \
libswresample \
}
arm {
#LIBS += -liconv
} else {
!arm {
LIBS += -lX11 -lXtst
}
@ -223,8 +240,10 @@ DEFINES += PROGRAM_VERSION=\\\"$$VERSION\\\"
# Input
HEADERS += folding.hh \
ankiconnector.h \
article_inspect.h \
articlewebpage.h \
base/globalregex.hh \
globalbroadcaster.h \
iframeschemehandler.h \
inc_case_folding.hh \
@ -364,8 +383,10 @@ FORMS += groups.ui \
fulltextsearch.ui
SOURCES += folding.cc \
ankiconnector.cpp \
article_inspect.cpp \
articlewebpage.cpp \
base/globalregex.cc \
globalbroadcaster.cpp \
iframeschemehandler.cpp \
main.cc \
@ -481,14 +502,11 @@ SOURCES += folding.cc \
win32 {
FORMS += texttospeechsource.ui
SOURCES += wordbyauto.cc \
guids.c \
SOURCES += guids.c \
speechclient_win.cc \
texttospeechsource.cc \
speechhlp.cc
HEADERS += wordbyauto.hh \
uiauto.hh \
texttospeechsource.hh \
HEADERS += texttospeechsource.hh \
sapi.hh \
sphelper.hh \
speechclient.hh \

View file

@ -468,10 +468,17 @@ void HotkeyWrapper::init()
{
keyToUngrab = grabbedKeys.end();
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
// We use RECORD extension instead of XGrabKey. That's because XGrabKey
// prevents other clients from getting their input if it's grabbed.
Display * display = QX11Info::display();
Display * display = displayID;
lShiftCode = XKeysymToKeycode( display, XK_Shift_L );
rShiftCode = XKeysymToKeycode( display, XK_Shift_R );
@ -678,13 +685,25 @@ public:
~X11GrabUngrabErrorHandler()
{
XFlush( QX11Info::display() );
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
XFlush( displayID );
(void) XSetErrorHandler( previousErrorHandler_ );
}
bool isError() const
{
XFlush( QX11Info::display() );
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
XFlush( displayID );
return error;
}
@ -706,8 +725,14 @@ HotkeyWrapper::GrabbedKeys::iterator HotkeyWrapper::grabKey( quint32 keyCode,
if ( result.second )
{
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
X11GrabUngrabErrorHandler errorHandler;
XGrabKey( QX11Info::display(), keyCode, modifiers, QX11Info::appRootWindow(),
XGrabKey( displayID, keyCode, modifiers, DefaultRootWindow(displayID),
True, GrabModeAsync, GrabModeAsync );
if ( errorHandler.isError() )
@ -722,8 +747,14 @@ HotkeyWrapper::GrabbedKeys::iterator HotkeyWrapper::grabKey( quint32 keyCode,
void HotkeyWrapper::ungrabKey( GrabbedKeys::iterator i )
{
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
X11GrabUngrabErrorHandler errorHandler;
XUngrabKey( QX11Info::display(), i->first, i->second, QX11Info::appRootWindow() );
XUngrabKey( displayID, i->first, i->second, XDefaultRootWindow(displayID) );
grabbedKeys.erase( i );
@ -746,14 +777,25 @@ quint32 HotkeyWrapper::nativeKey(int key)
keySymName = QKeySequence( key ).toString();
break;
}
Display * display = QX11Info::display();
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
Display * display = displayID;
return XKeysymToKeycode( display, XStringToKeysym( keySymName.toLatin1().data() ) );
}
void HotkeyWrapper::unregister()
{
Display * display = QX11Info::display();
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
Display * display = displayID;
XRecordDisableContext( display, recordContext );
XSync( display, False );

View file

@ -10,7 +10,7 @@
#include <X11/Xlib.h>
#include <X11/extensions/record.h>
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtGui/private/qtx11extras_p.h>
#include <QGuiApplication>
#else
#include <QX11Info>
#endif

View file

@ -0,0 +1,23 @@
# prerequisite
1. install anki
2. install ankiconnect
# configure anki
## 1. the model must have `Front` and `Back` fields
![Snipaste_2022-05-21_14-08-21](https://user-images.githubusercontent.com/105986/169638410-c6aa8038-df03-40de-8731-9f0b9f43bf59.png)
## 2. configure the template
the front template
![image](https://user-images.githubusercontent.com/105986/169638457-2358d020-0132-469f-a6b4-0fb6d1590fa2.png)
the back template
![image](https://user-images.githubusercontent.com/105986/169638440-7191fcdd-c338-48a3-a899-7216a5c77425.png)
# configure goldendict
## 1. through toolbar=>preference=>network
![image](https://user-images.githubusercontent.com/105986/169657672-d1affbde-e80e-4110-8fd9-55f2645c5ee1.png)
## 2. action
![image](https://user-images.githubusercontent.com/105986/169638740-abecde84-d33b-45ce-932c-d465c6650334.png)
## 3. result
![image](https://user-images.githubusercontent.com/105986/169638761-f67c009d-27cd-440d-bafa-ebbdce9577e3.png)

View file

@ -149,7 +149,7 @@ QString unescape( QString const & str, bool saveFormat )
{
tmp.replace( QRegularExpression( "<(?:\\s*/?(?:div|h[1-6r]|q|p(?![alr])|br|li(?![ns])|td|blockquote|[uo]l|pre|d[dl]|nav|address))[^>]{0,}>",
QRegularExpression::CaseInsensitiveOption ), " " );
tmp.remove( QRegularExpression( "<[^>]*>" ) );
tmp.replace( QRegularExpression( "<[^>]*>"), " ");
}
return QTextDocumentFragment::fromHtml( tmp.trimmed() ).toPlainText();
@ -157,6 +157,35 @@ QString unescape( QString const & str, bool saveFormat )
return str;
}
QString fromHtmlEscaped( QString const & str){
QString retVal = str;
QRegularExpression regExp("(?<lt>\\&lt\\;)|(?<gt>\\&gt\\;)|(?<amp>\\&amp\\;)|(?<quot>\\&quot\\;)", QRegularExpression::PatternOption::CaseInsensitiveOption);
auto match = regExp.match(str, 0);
while (match.hasMatch())
{
if (!match.captured("lt").isEmpty())
{
retVal.replace(match.capturedStart("lt"), match.capturedLength("lt"), "<");
}
else if (!match.captured("gt").isEmpty())
{
retVal.replace(match.capturedStart("gt"), match.capturedLength("gt"), ">");
}
else if (!match.captured("amp").isEmpty())
{
retVal.replace(match.capturedStart("amp"), match.capturedLength("amp"), "&");
}
else if (!match.captured("quot").isEmpty())
{
retVal.replace(match.capturedStart("quot"), match.capturedLength("quot"), "\"");
}
match = regExp.match(retVal, match.capturedStart() + 1);
}
return retVal;
}
string unescapeUtf8( const string &str, bool saveFormat )
{
return string( unescape( QString::fromUtf8( str.c_str(), str.size() ) ).toUtf8().data(), saveFormat );

View file

@ -4,6 +4,7 @@
#ifndef __HTMLESCAPE_HH_INCLUDED__
#define __HTMLESCAPE_HH_INCLUDED__
#include <QString>
#include <string>
namespace Html {
@ -24,6 +25,8 @@ string escapeForJavaScript( string const & );
// Replace html entities
QString unescape( QString const & str, bool saveFormat = false );
QString fromHtmlEscaped( QString const & str);
string unescapeUtf8( string const & str, bool saveFormat = false );
}

View file

@ -63,16 +63,16 @@ public:
{
}
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const &,
@ -91,11 +91,11 @@ public:
virtual bool isLocalDictionary()
{ return true; }
virtual vector< wstring > getAlternateWritings( const wstring & word ) throw();
virtual vector< wstring > getAlternateWritings( const wstring & word ) noexcept;
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -142,7 +142,7 @@ bool containsWhitespace( wstring const & str )
return false;
}
void HunspellDictionary::loadIcon() throw()
void HunspellDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -162,7 +162,7 @@ void HunspellDictionary::loadIcon() throw()
dictionaryIconLoaded = true;
}
vector< wstring > HunspellDictionary::getAlternateWritings( wstring const & word ) throw()
vector< wstring > HunspellDictionary::getAlternateWritings( wstring const & word ) noexcept
{
vector< wstring > results;

View file

@ -64,7 +64,7 @@ bool IndexedZip::loadFile( uint32_t offset, vector< char > & data )
if ( !ZipFile::readLocalHeader( zip, header ) )
{
GD_DPRINTF( "Failed to load header\n" );
GD_DPRINTF( "Failed to load header" );
return false;
}
@ -73,13 +73,13 @@ bool IndexedZip::loadFile( uint32_t offset, vector< char > & data )
switch( header.compressionMethod )
{
case ZipFile::Uncompressed:
GD_DPRINTF( "Uncompressed\n" );
GD_DPRINTF( "Uncompressed" );
data.resize( header.uncompressedSize );
return (size_t) zip.read( &data.front(), data.size() ) == data.size();
case ZipFile::Deflated:
{
GD_DPRINTF( "Deflated\n" );
GD_DPRINTF( "Deflated" );
// Now do the deflation

View file

@ -8,7 +8,7 @@
#include <windows.h>
#elif defined(HAVE_X11)
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtGui/private/qtx11extras_p.h>
#include <QGuiApplication>
#else
#include <QX11Info>
#endif
@ -44,9 +44,17 @@ bool KeyboardState::checkModifiersPressed( int mask )
( mask & Shift && !( keys & ( 1 << shiftKeyBit ) ) ) ||
( mask & Win && !( keys & ( 1 << controlKeyBit ) ) ) );
#else
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
XkbStateRec state;
XkbGetState( QX11Info::display(), XkbUseCoreKbd, &state );
XkbGetState( displayID, XkbUseCoreKbd, &state );
return !(
( mask & Alt && !( state.base_mods & Mod1Mask ) ) ||

View file

@ -240,7 +240,7 @@ void LoadDictionaries::handlePath( Config::Path const & path )
#endif
}
void LoadDictionaries::indexingDictionary( string const & dictionaryName ) throw()
void LoadDictionaries::indexingDictionary( string const & dictionaryName ) noexcept
{
emit indexingDictionarySignal( QString::fromUtf8( dictionaryName.c_str() ) );
}

View file

@ -46,7 +46,7 @@ signals:
public:
virtual void indexingDictionary( std::string const & dictionaryName ) throw();
virtual void indexingDictionary( std::string const & dictionaryName ) noexcept;
private:

View file

@ -39,6 +39,20 @@
<translation>(c) 2008-2013 Konstantin Isakov (ikm@goldendict.org)</translation>
</message>
</context>
<context>
<name>AnkiConnector</name>
<message>
<location filename="../ankiconnector.cpp" line="56"/>
<source>anki: post to anki failed</source>
<translatorcomment>anki:发布成功</translatorcomment>
<translation>anki:发布失败</translation>
</message>
<message>
<location filename="../ankiconnector.cpp" line="76"/>
<source>anki: post to anki success</source>
<translation>anki: 发布成功</translation>
</message>
</context>
<context>
<name>ArticleInspector</name>
<message>
@ -315,7 +329,17 @@
<translation></translation>
</message>
<message>
<location filename="../articleview.cc" line="1971"/>
<location filename="../articleview.cc" line="1853"/>
<source>Save &amp;Bookmark &quot;%1...&quot;</source>
<translation>&amp;S%1...</translation>
</message>
<message>
<location filename="../articleview.cc" line="1861"/>
<source>&amp;Send &quot;%1&quot; to anki with selected text.</source>
<translation>%1anki并附带选择的文本</translation>
</message>
<message>
<location filename="../articleview.cc" line="2016"/>
<source>Sound files (*.wav *.ogg *.oga *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)</source>
<translation>(*.wav *.ogg *.oga *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;*.*</translation>
</message>
@ -3903,7 +3927,27 @@ however, the article from the topmost dictionary is shown.</source>
<translation></translation>
</message>
<message>
<location filename="../preferences.ui" line="1147"/>
<location filename="../preferences.ui" line="1087"/>
<source>Anki Connect</source>
<translation>Anki连接</translation>
</message>
<message>
<location filename="../preferences.ui" line="1108"/>
<source>http://</source>
<translation>http://</translation>
</message>
<message>
<location filename="../preferences.ui" line="1152"/>
<source>Deck:</source>
<translation></translation>
</message>
<message>
<location filename="../preferences.ui" line="1162"/>
<source>Model:</source>
<translation></translation>
</message>
<message>
<location filename="../preferences.ui" line="1214"/>
<source>Some sites detect GoldenDict via HTTP headers and block the requests.
Enable this option to workaround the problem.</source>
<translation>使 GoldenDict UA</translation>
@ -4420,6 +4464,12 @@ from Stardict, Babylon and GLS dictionaries</source>
<source>Date: %1%2</source>
<translation>%1%2</translation>
</message>
<message>
<location filename="../ankiconnector.cpp" line="55"/>
<location filename="../ankiconnector.cpp" line="69"/>
<source>anki: post to anki failed</source>
<translation>anki:发布失败</translation>
</message>
</context>
<context>
<name>QuickFilterLine</name>

14
lsa.cc
View file

@ -164,15 +164,15 @@ public:
LsaDictionary( string const & id, string const & indexFile,
vector< string > const & dictionaryFiles );
virtual string getName() throw();
virtual string getName() noexcept;
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.soundsCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return getArticleCount(); }
virtual sptr< Dictionary::DataRequest > getArticle( wstring const &,
@ -186,10 +186,10 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
string LsaDictionary::getName() throw()
string LsaDictionary::getName() noexcept
{
string result = FsEncoding::basename( getDictionaryFilenames()[ 0 ] );
@ -498,7 +498,7 @@ sptr< Dictionary::DataRequest > LsaDictionary::getResource( string const & name
return dr;
}
void LsaDictionary::loadIcon() throw()
void LsaDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -253,7 +253,7 @@ int main( int argc, char ** argv )
#endif
QStringList localSchemes={"gdlookup","gdau","gico","qrcx","bres","bword","gdprg","gdvideo","gdpicture","gdtts","ifr"};
QStringList localSchemes={"gdlookup","gdau","gico","qrcx","bres","bword","gdprg","gdvideo","gdpicture","gdtts","ifr", "entry"};
for (int i = 0; i < localSchemes.size(); ++i)
{

View file

@ -60,9 +60,12 @@
#include "wstring_qt.hh"
#endif
#include <QWebEngineSettings>
#include <QWebEngineProfile>
#ifdef HAVE_X11
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
#include <QtGui/private/qtx11extras_p.h>
#include <QGuiApplication>
#else
#include <QX11Info>
#endif
@ -90,6 +93,19 @@ class InitSSLRunnable : public QRunnable
#endif
void MainWindow::changeWebEngineViewFont()
{
if( cfg.preferences.webFontFamily.isEmpty() )
{
QWebEngineProfile::defaultProfile()->settings()->resetFontFamily( QWebEngineSettings::StandardFont );
}
else
{
QWebEngineProfile::defaultProfile()->settings()->setFontFamily( QWebEngineSettings::StandardFont,
cfg.preferences.webFontFamily );
}
}
MainWindow::MainWindow( Config::Class & cfg_ ):
trayIcon( 0 ),
groupLabel( &searchPaneTitleBar ),
@ -148,6 +164,7 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
localSchemeHandler = new LocalSchemeHandler( articleNetMgr );
QWebEngineProfile::defaultProfile()->installUrlSchemeHandler( "gdlookup", localSchemeHandler );
QWebEngineProfile::defaultProfile()->installUrlSchemeHandler( "bword", localSchemeHandler );
QWebEngineProfile::defaultProfile()->installUrlSchemeHandler( "entry", localSchemeHandler );
iframeSchemeHandler = new IframeSchemeHandler( this );
QWebEngineProfile::defaultProfile()->installUrlSchemeHandler( "ifr", iframeSchemeHandler );
@ -761,6 +778,9 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
applyProxySettings();
//set webengineview font
changeWebEngineViewFont();
connect( &dictNetMgr, SIGNAL( proxyAuthenticationRequired( QNetworkProxy, QAuthenticator * ) ),
this, SLOT( proxyAuthentication( QNetworkProxy, QAuthenticator * ) ) );
@ -1225,6 +1245,10 @@ void MainWindow::closeEvent( QCloseEvent * ev )
void MainWindow::quitApp()
{
if( inspector && inspector->isVisible() )
{
inspector->close();
}
commitData();
qApp->quit();
}
@ -1393,6 +1417,7 @@ void MainWindow::updateGroupList()
groupList->fill( groupInstances );
groupList->setCurrentGroup( cfg.lastMainGroupId );
updateCurrentGroupProperty();
updateDictionaryBar();
@ -1612,9 +1637,10 @@ ArticleView * MainWindow::createNewTab( bool switchToIt,
groupList );
connect( view, &ArticleView::inspectSignal,this,[this](QWebEngineView * view){
if(inspector){
inspector->setInspectPage(view);
if( !inspector ){
inspector = new ArticleInspector( this );
}
inspector->setInspectPage( view );
});
connect( view, SIGNAL( titleChanged( ArticleView *, QString const & ) ),
@ -1666,6 +1692,7 @@ ArticleView * MainWindow::createNewTab( bool switchToIt,
connect( view, SIGNAL( zoomIn()), this, SLOT( zoomin() ) );
connect( view, SIGNAL( zoomOut()), this, SLOT( zoomout() ) );
connect( view, &ArticleView::saveBookmarkSignal, this, &MainWindow::addBookmarkToFavorite );
view->setSelectionBySingleClick( cfg.preferences.selectWordBySingleClick );
@ -2790,10 +2817,6 @@ void MainWindow::showTranslationFor( Config::InputPhrase const & phrase,
view->showDefinition( phrase, group, scrollTo );
updatePronounceAvailability();
updateFoundInDictsList();
updateBackForwardButtons();
//ui.tabWidget->setTabText( ui.tabWidget->indexOf(ui.tab), inWord.trimmed() );
}
@ -2815,11 +2838,6 @@ void MainWindow::showTranslationFor( QString const & inWord,
view->showDefinition( inWord, dictIDs, searchRegExp,
groupInstances[ groupList->currentIndex() ].id,
ignoreDiacritics );
updatePronounceAvailability();
updateFoundInDictsList();
updateBackForwardButtons();
}
#ifdef HAVE_X11
@ -2889,9 +2907,15 @@ void MainWindow::toggleMainWindow( bool onlyShow )
focusTranslateLine();
#ifdef HAVE_X11
#if QT_VERSION < 0x060000
Display *displayID = QX11Info::display();
#else
QNativeInterface::QX11Application *x11AppInfo = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11AppInfo->display();
#endif
Window wh = 0;
int rev = 0;
XGetInputFocus( QX11Info::display(), &wh, &rev );
XGetInputFocus( displayID, &wh, &rev );
if( wh != translateLine->internalWinId() && !byIconClick )
{
QPoint p( 1, 1 );
@ -2904,17 +2928,17 @@ void MainWindow::toggleMainWindow( bool onlyShow )
event.xbutton.x_root = p.x();
event.xbutton.y_root = p.y();
event.xbutton.window = internalWinId();
event.xbutton.root = QX11Info::appRootWindow( QX11Info::appScreen() );
event.xbutton.root = XDefaultRootWindow(displayID);
event.xbutton.state = Button1Mask;
event.xbutton.button = Button1;
event.xbutton.same_screen = true;
event.xbutton.time = CurrentTime;
XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event );
XFlush( QX11Info::display() );
XSendEvent( displayID, internalWinId(), true, 0xfff, &event );
XFlush( displayID );
event.type = ButtonRelease;
XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event );
XFlush( QX11Info::display() );
XSendEvent( displayID, internalWinId(), true, 0xfff, &event );
XFlush( displayID );
}
#endif
}
@ -2966,7 +2990,19 @@ void MainWindow::hotKeyActivated( int hk )
toggleMainWindow();
else
if ( scanPopup.get() )
{
#ifdef HAVE_X11
// When the user requests translation with the Ctrl+C+C hotkey in certain apps
// on some GNU/Linux systems, GoldenDict appears to handle Ctrl+C+C before the
// active application finishes handling Ctrl+C. As a result, GoldenDict finds
// the clipboard empty, silently cancels the translation request, and users report
// that Ctrl+C+C is broken in these apps. Slightly delay handling the clipboard
// hotkey to give the active application more time and thus work around the issue.
QTimer::singleShot( 10, scanPopup.get(), SLOT( translateWordFromClipboard() ) );
#else
scanPopup->translateWordFromClipboard();
#endif
}
}
void MainWindow::prepareNewReleaseChecks()
@ -3470,7 +3506,7 @@ void MainWindow::on_saveArticle_triggered()
// MDict anchors
QRegularExpression anchorLinkRe(
"(<\\s*a\\s+[^>]*\\b(?:name|id)\\b\\s*=\\s*[\"']*g[0-9a-f]{32}_)([0-9a-f]+_)(?=[^\"'])",
QRegularExpression::PatternOption::CaseInsensitiveOption );
QRegularExpression::PatternOption::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption );
html.replace( anchorLinkRe, "\\1" );
if( complete )
@ -4623,6 +4659,15 @@ void MainWindow::addWordToFavorites( QString const & word, unsigned groupId )
ui.favoritesPaneWidget->addHeadword( folder, word );
}
void MainWindow::addBookmarkToFavorite( QString const & text )
{
// get current tab word.
QString word = unescapeTabHeader( ui.tabWidget->tabText( ui.tabWidget->currentIndex() ) );
const auto bookmark = QString( "%1~~~%2" ).arg( word, text );
ui.favoritesPaneWidget->addHeadword( nullptr, bookmark );
}
void MainWindow::addAllTabsToFavorites()
{
QString folder;
@ -4695,8 +4740,22 @@ void MainWindow::headwordFromFavorites( QString const & headword,
}
// Show headword without lost of focus on Favorites tree
setTranslateBoxTextAndClearSuffix( headword, EscapeWildcards, DisablePopup );
showTranslationFor(headword );
// bookmark cases: the favorite item may like this "word~~~selectedtext"
auto words = headword.split( "~~~" );
setTranslateBoxTextAndClearSuffix( words[0], EscapeWildcards, DisablePopup );
//must be a bookmark.
if(words.size()>1)
{
auto view = getCurrentArticleView();
if(view)
{
view->setDelayedHighlightText(words[1]);// findText( words[ 1 ], QWebEnginePage::FindCaseSensitively );
}
}
showTranslationFor( words[ 0 ] );
}
#ifdef Q_OS_WIN32

View file

@ -260,6 +260,8 @@ private:
TranslateBoxPopup popupAction );
void setTranslateBoxTextAndClearSuffix( QString const & text, WildcardPolicy wildcardPolicy,
TranslateBoxPopup popupAction );
void changeWebEngineViewFont();
private slots:
void hotKeyActivated( int );
@ -460,6 +462,8 @@ private slots:
void addWordToFavorites( QString const & word, unsigned groupId );
void addBookmarkToFavorite( QString const & text );
bool isWordPresentedInFavorites( QString const & word, unsigned groupId );
void sendWordToInputLine( QString const & word );

View file

@ -336,6 +336,26 @@ bool MdictParser::readHeader( QDataStream & in )
headerTextUtf16.clear();
in.setByteOrder( QDataStream::BigEndian );
//parse stylesheet
QString styleSheets;
if( headerText.contains( "StyleSheet" ) )
{
// a workaround to bypass https://bugreports.qt.io/browse/QTBUG-102612
QRegularExpression rx( "StyleSheet=\"([^\"]*?)\"", QRegularExpression::CaseInsensitiveOption );
auto match = rx.match( headerText );
if( match.hasMatch() || match.hasPartialMatch() )
{
styleSheets = match.captured( 1 );
}
}
//with this control character ,qt6.x can not parse attribute value.
headerText.remove(QRegularExpression("\\p{C}"));
QDomNamedNodeMap headerAttributes = parseHeaderAttributes( headerText );
encoding_ = headerAttributes.namedItem( "Encoding" ).toAttr().value();
@ -352,32 +372,14 @@ bool MdictParser::readHeader( QDataStream & in )
// styleId # 1-255
// style.prefix
// style.suffix
if ( headerAttributes.contains( "StyleSheet" ) )
if ( !styleSheets.isEmpty() )
{
#if( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
//a workaround to bypass https://bugreports.qt.io/browse/QTBUG-102612
QRegularExpression rx( "StyleSheet=\"([^\"]*?)\"", QRegularExpression::CaseInsensitiveOption );
auto match = rx.match( headerText );
QString styleSheets;
if( match.hasMatch() || match.hasPartialMatch() )
{
styleSheets = match.captured( 1 );
}
#else
QString styleSheets = headerAttributes.namedItem( "StyleSheet" ).toAttr().value();
#endif
QStringList lines = styleSheets.split( QRegularExpression( "[\r\n]" ), Qt::KeepEmptyParts );
for( int i = 0; i < lines.size() - 3; i += 3 )
{
#if( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
styleSheets_[ lines[ i ].toInt() ] =
pair< QString, QString >( Html::unescape( lines[ i + 1 ] ), Html::unescape( lines[ i + 2 ] ) );
#else
styleSheets_[ lines[ i ].toInt() ] = pair< QString, QString >( lines[ i + 1 ], lines[ i + 2 ] );
#endif
pair( Html::fromHtmlEscaped( lines[ i + 1 ] ), Html::fromHtmlEscaped( lines[ i + 2 ] ) );
}
}

View file

@ -173,7 +173,7 @@ public:
{
QString s = QString::fromUtf8( article.c_str() );
substituteStylesheet( s, styleSheets );
return string( s.toUtf8().constData() );
return s.toStdString();
}
protected:

139
mdx.cc
View file

@ -42,6 +42,7 @@
#include "tiff.hh"
#include "utils.hh"
#include "base/globalregex.hh"
namespace Mdx
{
@ -162,7 +163,7 @@ public:
MdictParser::RecordInfo indexEntry;
vector< char > chunk;
Mutex::Lock _( idxMutex );
// Mutex::Lock _( idxMutex );
const char * indexEntryPtr = chunks.getBlock( links[ 0 ].articleOffset, chunk );
memcpy( &indexEntry, indexEntryPtr, sizeof( indexEntry ) );
@ -192,51 +193,6 @@ public:
};
struct MdxRegex
{
MdxRegex() :
allLinksRe( "(?:<\\s*(a(?:rea)?|img|link|script|source)(?:\\s+[^>]+|\\s*)>)",
QRegularExpression::CaseInsensitiveOption ),
wordCrossLink( "([\\s\"']href\\s*=)\\s*([\"'])entry://([^>#]*?)((?:#[^>]*?)?)\\2",
QRegularExpression::CaseInsensitiveOption ),
anchorIdRe( "([\\s\"'](?:name|id)\\s*=)\\s*([\"'])\\s*(?=\\S)", QRegularExpression::CaseInsensitiveOption ),
anchorIdReWord( "([\\s\"'](?:name|id)\\s*=)\\s*([\"'])\\s*(?=\\S)([^\"]*)", QRegularExpression::CaseInsensitiveOption ),
anchorIdRe2( "([\\s\"'](?:name|id)\\s*=)\\s*(?=[^\"'])([^\\s\">]+)", QRegularExpression::CaseInsensitiveOption ),
anchorLinkRe( "([\\s\"']href\\s*=\\s*[\"'])entry://#", QRegularExpression::CaseInsensitiveOption ),
audioRe( "([\\s\"']href\\s*=)\\s*([\"'])sound://([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption ),
stylesRe( "([\\s\"']href\\s*=)\\s*([\"'])(?!\\s*\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption ),
stylesRe2( "([\\s\"']href\\s*=)\\s*(?![\\s\"']|\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\\s\">]+)",
QRegularExpression::CaseInsensitiveOption ),
inlineScriptRe( "<\\s*script(?:(?=\\s)(?:(?![\\s\"']src\\s*=)[^>])+|\\s*)>",
QRegularExpression::CaseInsensitiveOption ),
closeScriptTagRe( "<\\s*/script\\s*>", QRegularExpression::CaseInsensitiveOption ),
srcRe( "([\\s\"']src\\s*=)\\s*([\"'])(?!\\s*\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\">]+)\\2",
QRegularExpression::CaseInsensitiveOption ),
srcRe2( "([\\s\"']src\\s*=)\\s*(?![\\s\"']|\\b(?:(?:bres|https?|ftp)://"
"|(?:data|javascript):))(?:file://)?[\\x00-\\x1f\\x7f]*\\.*/?([^\\s\">]+)",
QRegularExpression::CaseInsensitiveOption )
{
}
QRegularExpression allLinksRe;
QRegularExpression wordCrossLink;
QRegularExpression anchorIdRe;
QRegularExpression anchorIdReWord;
QRegularExpression anchorIdRe2;
QRegularExpression anchorLinkRe;
QRegularExpression audioRe;
QRegularExpression stylesRe;
QRegularExpression stylesRe2;
QRegularExpression inlineScriptRe;
QRegularExpression closeScriptTagRe;
QRegularExpression srcRe;
QRegularExpression srcRe2;
};
class MdxDictionary: public BtreeIndexing::BtreeDictionary
{
Mutex idxMutex;
@ -256,8 +212,6 @@ class MdxDictionary: public BtreeIndexing::BtreeDictionary
string initError;
QString cacheDirName;
static MdxRegex mdxRx;
public:
MdxDictionary( string const & id, string const & indexFile, vector<string> const & dictionaryFiles );
@ -266,22 +220,22 @@ public:
virtual void deferredInit();
virtual string getName() throw()
virtual string getName() noexcept
{
return dictionaryName;
}
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{
return map< Dictionary::Property, string >();
}
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{
return idxHeader.articleCount;
}
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{
return idxHeader.wordCount;
}
@ -327,7 +281,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -347,8 +301,6 @@ private:
friend class MddResourceRequest;
};
MdxRegex MdxDictionary::mdxRx;
MdxDictionary::MdxDictionary( string const & id, string const & indexFile,
vector<string> const & dictionaryFiles ):
BtreeDictionary( id, dictionaryFiles ),
@ -847,14 +799,14 @@ void MddResourceRequest::run()
{
QString css = QString::fromUtf8( data.data(), data.size() );
QRegularExpression links( "url\\(\\s*(['\"]?)([^'\"]*)(['\"]?)\\s*\\)",
QRegularExpression::CaseInsensitiveOption );
// QRegularExpression links( "url\\(\\s*(['\"]?)([^'\"]*)(['\"]?)\\s*\\)",
// QRegularExpression::CaseInsensitiveOption );
QString id = QString::fromUtf8( dict.getId().c_str() );
int pos = 0;
QString newCSS;
QRegularExpressionMatchIterator it = links.globalMatch( css );
QRegularExpressionMatchIterator it = RX::Mdx::links.globalMatch( css );
while ( it.hasNext() )
{
QRegularExpressionMatch match = it.next();
@ -915,7 +867,7 @@ const QString & MdxDictionary::getDescription()
}
else
{
Mutex::Lock _( idxMutex );
// Mutex::Lock _( idxMutex );
vector< char > chunk;
char * dictDescription = chunks.getBlock( idxHeader.descriptionAddress, chunk );
string str( dictDescription );
@ -925,7 +877,7 @@ const QString & MdxDictionary::getDescription()
return dictionaryDescription;
}
void MdxDictionary::loadIcon() throw()
void MdxDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -948,7 +900,7 @@ void MdxDictionary::loadIcon() throw()
void MdxDictionary::loadArticle( uint32_t offset, string & articleText, bool noFilter )
{
vector< char > chunk;
Mutex::Lock _( idxMutex );
// Mutex::Lock _( idxMutex );
// Load record info from index
MdictParser::RecordInfo recordInfo;
@ -959,25 +911,32 @@ void MdxDictionary::loadArticle( uint32_t offset, string & articleText, bool noF
QString articleId;
articleId.setNum( ( quint64 )pRecordInfo, 16 );
ScopedMemMap compressed( dictFile, recordInfo.compressedBlockPos, recordInfo.compressedBlockSize );
if ( !compressed.startAddress() )
throw exCorruptDictionary();
QByteArray decompressed;
if ( !MdictParser::parseCompressedBlock( recordInfo.compressedBlockSize, ( char * )compressed.startAddress(),
recordInfo.decompressedBlockSize, decompressed ) )
throw exCorruptDictionary();
{
Mutex::Lock _( idxMutex );
ScopedMemMap compressed( dictFile, recordInfo.compressedBlockPos, recordInfo.compressedBlockSize );
if( !compressed.startAddress() )
throw exCorruptDictionary();
if( !MdictParser::parseCompressedBlock( recordInfo.compressedBlockSize,
(char *)compressed.startAddress(),
recordInfo.decompressedBlockSize,
decompressed ) )
throw exCorruptDictionary();
}
QString article = MdictParser::toUtf16( encoding.c_str(),
decompressed.constData() + recordInfo.recordOffset,
recordInfo.recordSize );
article = MdictParser::substituteStylesheet( article, styleSheets );
if( !noFilter )
{
article = MdictParser::substituteStylesheet( article, styleSheets );
article = filterResource( articleId, article );
}
articleText = string( article.toUtf8().constData() );
articleText = article.toStdString();
}
QString & MdxDictionary::filterResource( QString const & articleId, QString & article )
@ -987,7 +946,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
QString articleNewText;
int linkPos = 0;
QRegularExpressionMatchIterator it = mdxRx.allLinksRe.globalMatch( article );
QRegularExpressionMatchIterator it = RX::Mdx::allLinksRe.globalMatch( article );
QMap<QString,QString> idMap;
while( it.hasNext() )
{
@ -1005,10 +964,10 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
if( !linkType.isEmpty() && linkType.at( 0 ) == 'a' )
{
QRegularExpressionMatch match = mdxRx.anchorIdRe.match( linkTxt );
QRegularExpressionMatch match = RX::Mdx::anchorIdRe.match( linkTxt );
if( match.hasMatch() )
{
auto wordMatch = mdxRx.anchorIdReWord.match( linkTxt );
auto wordMatch = RX::Mdx::anchorIdReWord.match( linkTxt );
if( wordMatch.hasMatch() )
{
idMap.insert( wordMatch.captured( 3 ), uniquePrefix + wordMatch.captured( 3 ) );
@ -1017,11 +976,11 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
newLink = linkTxt.replace( match.capturedStart(), match.capturedLength(), newText );
}
else
newLink = linkTxt.replace( mdxRx.anchorIdRe2, "\\1\"" + uniquePrefix + "\\2\"" );
newLink = linkTxt.replace( RX::Mdx::anchorIdRe2, "\\1\"" + uniquePrefix + "\\2\"" );
newLink = newLink.replace( mdxRx.anchorLinkRe, "\\1#" + uniquePrefix );
newLink = newLink.replace( RX::Mdx::anchorLinkRe, "\\1#" + uniquePrefix );
match = mdxRx.audioRe.match( newLink );
match = RX::Mdx::audioRe.match( newLink );
if( match.hasMatch() )
{
// sounds and audio link script
@ -1032,7 +991,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
+ newLink.replace( match.capturedStart(), match.capturedLength(), newTxt );
}
match = mdxRx.wordCrossLink.match( newLink );
match = RX::Mdx::wordCrossLink.match( newLink );
if( match.hasMatch() )
{
QString newTxt = match.captured( 1 ) + match.captured( 2 )
@ -1050,7 +1009,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
if( linkType.compare( "link" ) == 0 )
{
// stylesheets
QRegularExpressionMatch match = mdxRx.stylesRe.match( linkTxt );
QRegularExpressionMatch match = RX::Mdx::stylesRe.match( linkTxt );
if( match.hasMatch() )
{
QString newText = match.captured( 1 ) + match.captured( 2 )
@ -1059,7 +1018,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
newLink = linkTxt.replace( match.capturedStart(), match.capturedLength(), newText );
}
else
newLink = linkTxt.replace( mdxRx.stylesRe2,
newLink = linkTxt.replace( RX::Mdx::stylesRe2,
"\\1\"bres://" + id + "/\\2\"" );
}
else
@ -1067,13 +1026,13 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
|| linkType.compare( "source" ) == 0 )
{
// javascripts and images
QRegularExpressionMatch match = mdxRx.inlineScriptRe.match( linkTxt );
QRegularExpressionMatch match = RX::Mdx::inlineScriptRe.match( linkTxt );
if( linkType.at( 1 ) == 'c' // "script" tag
&& match.hasMatch() && match.capturedLength() == linkTxt.length() )
{
// skip inline scripts
articleNewText += linkTxt;
match = mdxRx.closeScriptTagRe.match( article, linkPos );
match = RX::Mdx::closeScriptTagRe.match( article, linkPos );
if( match.hasMatch() )
{
articleNewText += article.mid( linkPos, match.capturedEnd() - linkPos );
@ -1083,7 +1042,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
}
else
{
match = mdxRx.srcRe.match( linkTxt );
match = RX::Mdx::srcRe.match( linkTxt );
if( match.hasMatch() )
{
QString newText;
@ -1104,7 +1063,7 @@ QString & MdxDictionary::filterResource( QString const & articleId, QString & ar
newLink = linkTxt.replace( match.capturedStart(), match.capturedLength(), newText );
}
else
newLink = linkTxt.replace( mdxRx.srcRe2,
newLink = linkTxt.replace( RX::Mdx::srcRe2,
"\\1\"bres://" + id + "/\\2\"" );
}
}
@ -1409,7 +1368,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
if ( !parser.open( i->c_str() ) )
continue;
string title = string( parser.title().toUtf8().constData() );
string title = parser.title().toStdString();
initializing.indexingDictionary( title );
for ( vector< string >::const_iterator mddIter = dictFiles.begin() + 1;
@ -1440,7 +1399,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
// then the encoding
{
string encoding = string( parser.encoding().toUtf8().constData() );
string encoding = parser.encoding().toStdString();
idx.write< uint32_t >( encoding.size() );
idx.write( encoding.data(), encoding.size() );
}
@ -1457,7 +1416,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
// Save dictionary description if there's one
{
string description = string( parser.description().toUtf8().constData() );
string description = parser.description().toStdString();
idxHeader.descriptionAddress = chunks.startNewBlock();
chunks.addToBlock( description.c_str(), description.size() + 1 );
idxHeader.descriptionSize = description.size() + 1;
@ -1491,7 +1450,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
mddIndices.push_back( mddIndexedWords );
// Save filename for .mdd files only
QFileInfo fi( mddParser->filename() );
mddFileNames.push_back( string( fi.fileName().toUtf8().constData() ) );
mddFileNames.push_back( fi.fileName().toStdString() );
mddParsers.pop_front();
}
@ -1514,8 +1473,8 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
for ( MdictParser::StyleSheets::const_iterator iter = styleSheets.begin();
iter != styleSheets.end(); ++iter )
{
string styleBegin( iter->second.first.toUtf8().constData() );
string styleEnd( iter->second.second.toUtf8().constData() );
string styleBegin(iter->second.first.toStdString());
string styleEnd( iter->second.second.toStdString() );
// key
idx.write<qint32>( iter->first );

View file

@ -47,16 +47,16 @@ public:
langId = LangCoder::code2toInt( url.mid( n - 2, 2 ).toLatin1().data() );
}
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const &,
@ -73,11 +73,11 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
void MediaWikiDictionary::loadIcon() throw()
void MediaWikiDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -4,16 +4,16 @@
#ifndef __MUTEX_HH_INCLUDED__
#define __MUTEX_HH_INCLUDED__
#include <QRecursiveMutex>
#include <QMutex>
/// This provides a mutex class. As you can see, it's just a Qt one, but it
/// does provide the Lock class which doesn't seem to exist in Qt, and it does
/// provide some abstraction for dictionaries in case they are to be ported
/// away from Qt.
class Mutex : public QRecursiveMutex
class Mutex : public QMutex
{
public:
Mutex() : QRecursiveMutex()
Mutex() : QMutex()
{}
~Mutex()
{}

View file

@ -323,6 +323,13 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
ui.customSettingsGroup->setEnabled( p.proxyServer.enabled );
}
//anki connect
ui.useAnkiConnect->setChecked( p.ankiConnectServer.enabled );
ui.ankiHost->setText( p.ankiConnectServer.host );
ui.ankiPort->setValue( p.ankiConnectServer.port );
ui.ankiModel->setText( p.ankiConnectServer.model );
ui.ankiDeck->setText(p.ankiConnectServer.deck);
connect( ui.customProxy, SIGNAL( toggled( bool ) ),
this, SLOT( customProxyToggled( bool ) ) );
@ -466,6 +473,13 @@ Config::Preferences Preferences::getPreferences()
p.proxyServer.user = ui.proxyUser->text();
p.proxyServer.password = ui.proxyPassword->text();
//anki connect
p.ankiConnectServer.enabled = ui.useAnkiConnect->isChecked();
p.ankiConnectServer.host = ui.ankiHost->text();
p.ankiConnectServer.port = (unsigned)ui.ankiPort->value();
p.ankiConnectServer.deck = ui.ankiDeck->text();
p.ankiConnectServer.model = ui.ankiModel->text();
p.checkForNewReleases = ui.checkForNewReleases->isChecked();
p.disallowContentFromOtherSites = ui.disallowContentFromOtherSites->isChecked();
p.enableWebPlugins = ui.enableWebPlugins->isChecked();

View file

@ -993,6 +993,9 @@ for all program's network requests.</string>
</item>
<item>
<widget class="QGroupBox" name="customSettingsGroup">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Custom settings</string>
</property>
@ -1011,6 +1014,9 @@ for all program's network requests.</string>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Host:</string>
</property>
@ -1073,20 +1079,110 @@ for all program's network requests.</string>
</widget>
</item>
<item>
<spacer name="verticalSpacer_14">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QGroupBox" name="useAnkiConnect">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<property name="title">
<string>Anki Connect</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
<property name="checkable">
<bool>true</bool>
</property>
</spacer>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_21">
<item>
<widget class="QLabel" name="label_22">
<property name="text">
<string>Host:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>http://</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ankiHost"/>
</item>
<item>
<widget class="QLabel" name="label_23">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="ankiPort">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>8080</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_22">
<item>
<widget class="QLabel" name="label_28">
<property name="text">
<string>Deck:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ankiDeck"/>
</item>
<item>
<widget class="QLabel" name="label_25">
<property name="text">
<string>Model:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ankiModel"/>
</item>
<item>
<spacer name="horizontalSpacer_17">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="disallowContentFromOtherSites">
@ -1176,22 +1272,6 @@ clears its network cache from disk during exit.</string>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkForNewReleases">
<property name="toolTip">

View file

@ -30,16 +30,16 @@ public:
{
}
virtual string getName() throw()
virtual string getName() noexcept
{ return prg.name.toUtf8().data(); }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const & word,
@ -53,7 +53,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
sptr< WordSearchRequest > ProgramsDictionary::prefixMatch( wstring const & word,
@ -118,7 +118,7 @@ sptr< Dictionary::DataRequest > ProgramsDictionary::getArticle(
}
}
void ProgramsDictionary::loadIcon() throw()
void ProgramsDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -6,6 +6,11 @@ $(function() {
if ('string' != typeof(link)) {
return;
}
if(link.indexOf("javascript:")>=0){
return;
}
if(link.indexOf(":")>=0){
emitClickedEvent(link);
return false;

View file

@ -143,16 +143,16 @@ class SdictDictionary: public BtreeIndexing::BtreeDictionary
~SdictDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -187,7 +187,7 @@ class SdictDictionary: public BtreeIndexing::BtreeDictionary
}
protected:
void loadIcon() throw();
void loadIcon() noexcept;
private:
@ -240,7 +240,7 @@ SdictDictionary::~SdictDictionary()
df.close();
}
void SdictDictionary::loadIcon() throw()
void SdictDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

18
slob.cc
View file

@ -587,16 +587,16 @@ class SlobDictionary: public BtreeIndexing::BtreeDictionary
~SlobDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -643,7 +643,7 @@ class SlobDictionary: public BtreeIndexing::BtreeDictionary
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -694,12 +694,12 @@ SlobDictionary::SlobDictionary( string const & id,
// Read dictionary name
dictionaryName = string( sf.getDictionaryName().toUtf8().constData() );
dictionaryName = sf.getDictionaryName().toStdString();
if( dictionaryName.empty() )
{
QString name = QDir::fromNativeSeparators( FsEncoding::decode( dictionaryFiles[ 0 ].c_str() ) );
int n = name.lastIndexOf( '/' );
dictionaryName = string( name.mid( n + 1 ).toUtf8().constData() );
dictionaryName = name.mid( n + 1 ).toStdString();
}
// Full-text search parameters
@ -746,7 +746,7 @@ void SlobDictionary::removeDirectory( QString const & directory )
dir.rmdir( directory );
}
void SlobDictionary::loadIcon() throw()
void SlobDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -799,7 +799,7 @@ void SlobDictionary::loadArticle( quint32 address,
articleText = convert( articleText, entry );
}
else
articleText = string( QObject::tr( "Article decoding error" ).toUtf8().constData() );
articleText = QObject::tr( "Article decoding error" ).toStdString();
// See Issue #271: A mechanism to clean-up invalid HTML cards.
string cleaner = "</font>""</font>""</font>""</font>""</font>""</font>"

View file

@ -79,16 +79,16 @@ public:
vector< string > const & dictionaryFiles,
QString const & iconFilename_ );
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.soundsCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return getArticleCount(); }
virtual sptr< Dictionary::DataRequest > getArticle( wstring const &,
@ -102,7 +102,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
SoundDirDictionary::SoundDirDictionary( string const & id,
@ -289,7 +289,7 @@ sptr< Dictionary::DataRequest > SoundDirDictionary::getArticle( wstring const &
return ret;
}
void SoundDirDictionary::loadIcon() throw()
void SoundDirDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -155,16 +155,16 @@ public:
~StardictDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return bookName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.wordCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount + idxHeader.synWordCount; }
inline virtual quint32 getLangFrom() const
@ -207,7 +207,7 @@ public:
}
protected:
void loadIcon() throw();
void loadIcon() noexcept;
private:
@ -292,7 +292,7 @@ StardictDictionary::~StardictDictionary()
dict_data_close( dz );
}
void StardictDictionary::loadIcon() throw()
void StardictDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -22,16 +22,16 @@ BaseTransliterationDictionary::BaseTransliterationDictionary( string const & id,
dictionaryIconLoaded = true;
}
string BaseTransliterationDictionary::getName() throw()
string BaseTransliterationDictionary::getName() noexcept
{ return name; }
map< Dictionary::Property, string > BaseTransliterationDictionary::getProperties() throw()
map< Dictionary::Property, string > BaseTransliterationDictionary::getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
unsigned long BaseTransliterationDictionary::getArticleCount() throw()
unsigned long BaseTransliterationDictionary::getArticleCount() noexcept
{ return 0; }
unsigned long BaseTransliterationDictionary::getWordCount() throw()
unsigned long BaseTransliterationDictionary::getWordCount() noexcept
{ return 0; }
sptr< Dictionary::WordSearchRequest > BaseTransliterationDictionary::prefixMatch( wstring const &,
@ -83,7 +83,7 @@ TransliterationDictionary::TransliterationDictionary( string const & id,
}
vector< wstring > TransliterationDictionary::getAlternateWritings( wstring const & str )
throw()
noexcept
{
vector< wstring > results;

View file

@ -28,16 +28,16 @@ public:
BaseTransliterationDictionary( string const & id, string const & name,
QIcon icon, bool caseSensitive = true );
virtual string getName() throw();
virtual string getName() noexcept;
virtual map< Dictionary::Property, string > getProperties() throw();
virtual map< Dictionary::Property, string > getProperties() noexcept;
virtual unsigned long getArticleCount() throw();
virtual unsigned long getArticleCount() noexcept;
virtual unsigned long getWordCount() throw();
virtual unsigned long getWordCount() noexcept;
virtual vector< wstring > getAlternateWritings( wstring const & )
throw() = 0;
noexcept = 0;
virtual sptr< Dictionary::WordSearchRequest > findHeadwordsForSynonym( wstring const & )
;
@ -85,7 +85,7 @@ public:
bool caseSensitive = true );
virtual vector< wstring > getAlternateWritings( wstring const & )
throw();
noexcept;
};
}

334
uiauto.hh
View file

@ -1,334 +0,0 @@
#ifndef __UIAUTO_HH_INCLUDED__
#define __UIAUTO_HH_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
#include <oleacc.h>
EXTERN_C const IID IID_IUIAutomation;
EXTERN_C const IID CLSID_CUIAutomation;
EXTERN_C const IID IID_IUIAutomationElement;
EXTERN_C const IID IID_IUIAutomationTextPattern;
EXTERN_C const IID IID_IUIAutomationTextRange;
EXTERN_C const IID IID_IUIAutomationTreeWalker;
typedef interface IUIAutomationElement IUIAutomationElement;
typedef interface IUIAutomationElementArray IUIAutomationElementArray;
typedef interface IUIAutomationTextPattern IUIAutomationTextPattern;
typedef interface IUIAutomationTextRange IUIAutomationTextRange;
typedef interface IUIAutomationTextRangeArray IUIAutomationTextRangeArray;
typedef interface IUIAutomationCacheRequest IUIAutomationCacheRequest;
typedef interface IUIAutomationTreeWalker IUIAutomationTreeWalker;
typedef interface IUIAutomationCondition IUIAutomationCondition;
typedef interface IUIAutomationEventHandler IUIAutomationEventHandler;
typedef interface IUIAutomationPropertyChangedEventHandler IUIAutomationPropertyChangedEventHandler;
typedef interface IUIAutomationStructureChangedEventHandler IUIAutomationStructureChangedEventHandler;
typedef interface IUIAutomationFocusChangedEventHandler IUIAutomationFocusChangedEventHandler;
typedef interface IUIAutomationProxyFactory IUIAutomationProxyFactory;
typedef interface IUIAutomationProxyFactoryEntry IUIAutomationProxyFactoryEntry;
typedef interface IUIAutomationProxyFactoryMapping IUIAutomationProxyFactoryMapping;
typedef void *UIA_HWND;
typedef int PROPERTYID;
typedef int EVENTID;
typedef int PATTERNID;
typedef int CONTROLTYPEID;
typedef int TEXTATTRIBUTEID;
enum TreeScope
{
TreeScope_Element = 0x1,
TreeScope_Children = 0x2,
TreeScope_Descendants = 0x4,
TreeScope_Parent = 0x8,
TreeScope_Ancestors = 0x10,
TreeScope_Subtree = ( ( TreeScope_Element | TreeScope_Children ) | TreeScope_Descendants )
};
enum PropertyConditionFlags
{
PropertyConditionFlags_None = 0,
PropertyConditionFlags_IgnoreCase = 0x1
};
enum OrientationType
{
OrientationType_None = 0,
OrientationType_Horizontal = 1,
OrientationType_Vertical = 2
};
enum SupportedTextSelection
{
SupportedTextSelection_None = 0,
SupportedTextSelection_Single = 1,
SupportedTextSelection_Multiple = 2
};
enum TextPatternRangeEndpoint
{
TextPatternRangeEndpoint_Start = 0,
TextPatternRangeEndpoint_End = 1
};
enum TextUnit
{
TextUnit_Character = 0,
TextUnit_Format = 1,
TextUnit_Word = 2,
TextUnit_Line = 3,
TextUnit_Paragraph = 4,
TextUnit_Page = 5,
TextUnit_Document = 6
};
enum ProviderOptions
{
ProviderOptions_ClientSideProvider = 0x1,
ProviderOptions_ServerSideProvider = 0x2,
ProviderOptions_NonClientAreaProvider = 0x4,
ProviderOptions_OverrideProvider = 0x8,
ProviderOptions_ProviderOwnsSetFocus = 0x10,
ProviderOptions_UseComThreading = 0x20
} ;
/* UIA_PatternIds */
const long UIA_InvokePatternId = 10000;
const long UIA_SelectionPatternId = 10001;
const long UIA_ValuePatternId = 10002;
const long UIA_RangeValuePatternId = 10003;
const long UIA_ScrollPatternId = 10004;
const long UIA_ExpandCollapsePatternId = 10005;
const long UIA_GridPatternId = 10006;
const long UIA_GridItemPatternId = 10007;
const long UIA_MultipleViewPatternId = 10008;
const long UIA_WindowPatternId = 10009;
const long UIA_SelectionItemPatternId = 10010;
const long UIA_DockPatternId = 10011;
const long UIA_TablePatternId = 10012;
const long UIA_TableItemPatternId = 10013;
const long UIA_TextPatternId = 10014;
const long UIA_TogglePatternId = 10015;
const long UIA_TransformPatternId = 10016;
const long UIA_ScrollItemPatternId = 10017;
const long UIA_LegacyIAccessiblePatternId = 10018;
const long UIA_ItemContainerPatternId = 10019;
const long UIA_VirtualizedItemPatternId = 10020;
const long UIA_SynchronizedInputPatternId = 10021;
#ifdef INTERFACE
#undef INTERFACE
#endif
#define INTERFACE IUIAutomation
DECLARE_INTERFACE_(IUIAutomation, IUnknown)
{
STDMETHOD(CompareElements)(THIS_ IUIAutomationElement *, IUIAutomationElement *, BOOL *) PURE;
STDMETHOD(CompareRuntimeIds)(THIS_ SAFEARRAY *, SAFEARRAY *, BOOL *) PURE;
STDMETHOD(GetRootElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(ElementFromHandle)(THIS_ UIA_HWND, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromPoint)(THIS_ POINT, IUIAutomationElement **) PURE;
STDMETHOD(GetFocusedElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetRootElementBuildCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromHandleBuildCache)(THIS_ UIA_HWND, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromPointBuildCache)(THIS_ POINT, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetFocusedElementBuildCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(CreateTreeWalker)(THIS_ IUIAutomationCondition *, IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_ControlViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_ContentViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_RawViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_RawViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(get_ControlViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(get_ContentViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreateCacheRequest)(THIS_ IUIAutomationCacheRequest **) PURE;
STDMETHOD(CreateTrueCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreateFalseCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreatePropertyCondition)(THIS_ PROPERTYID, VARIANT, IUIAutomationCondition **) PURE;
STDMETHOD(CreatePropertyConditionEx)(THIS_ PROPERTYID, VARIANT, enum PropertyConditionFlags, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndConditionFromArray)(THIS_ SAFEARRAY *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndConditionFromNativeArray)(THIS_ IUIAutomationCondition **, int , IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrConditionFromArray)(THIS_ SAFEARRAY *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrConditionFromNativeArray)(THIS_ IUIAutomationCondition **, int , IUIAutomationCondition **) PURE;
STDMETHOD(CreateNotCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(AddAutomationEventHandler)(THIS_ EVENTID, IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *, IUIAutomationEventHandler *) PURE;
STDMETHOD(RemoveAutomationEventHandler)(THIS_ EVENTID, IUIAutomationElement *, IUIAutomationEventHandler *) PURE;
STDMETHOD(AddPropertyChangedEventHandlerNativeArray)(THIS_ IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *,
IUIAutomationPropertyChangedEventHandler *, PROPERTYID *, int) PURE;
STDMETHOD(AddPropertyChangedEventHandler)(THIS_ IUIAutomationElement *, enum TreeScope, EVENTID, IUIAutomationCacheRequest *,
IUIAutomationPropertyChangedEventHandler *, SAFEARRAY *) PURE;
STDMETHOD(RemovePropertyChangedEventHandler)(THIS_ IUIAutomationElement *, IUIAutomationPropertyChangedEventHandler *) PURE;
STDMETHOD(AddStructureChangedEventHandler)(THIS_ IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *, IUIAutomationStructureChangedEventHandler *) PURE;
STDMETHOD(RemoveStructureChangedEventHandler)(THIS_ IUIAutomationElement *, IUIAutomationStructureChangedEventHandler *) PURE;
STDMETHOD(AddFocusChangedEventHandler)(THIS_ IUIAutomationCacheRequest *, IUIAutomationFocusChangedEventHandler *) PURE;
STDMETHOD(RemoveFocusChangedEventHandler)(THIS_ IUIAutomationFocusChangedEventHandler *) PURE;
STDMETHOD(RemoveAllEventHandlers)(THIS) PURE;
STDMETHOD(IntNativeArrayToSafeArray)(THIS_ int *, int, SAFEARRAY **) PURE;
STDMETHOD(IntSafeArrayToNativeArray)(THIS_ SAFEARRAY *, int **, int *) PURE;
STDMETHOD(RectToVariant)(THIS_ RECT, VARIANT *) PURE;
STDMETHOD(VariantToRect)(THIS_ VARIANT, RECT *) PURE;
STDMETHOD(SafeArrayToRectNativeArray)(THIS_ SAFEARRAY *, RECT **, int *) PURE;
STDMETHOD(CreateProxyFactoryEntry)(THIS_ IUIAutomationProxyFactory *, IUIAutomationProxyFactoryEntry **) PURE;
STDMETHOD(get_ProxyFactoryMapping)(THIS_ IUIAutomationProxyFactoryMapping **) PURE;
STDMETHOD(GetPropertyProgrammaticName)(THIS_ PROPERTYID, BSTR *) PURE;
STDMETHOD(GetPatternProgrammaticName)(THIS_ PATTERNID, BSTR *) PURE;
STDMETHOD(PollForPotentialSupportedPatterns)(THIS_ IUIAutomationElement *, SAFEARRAY **, SAFEARRAY **) PURE;
STDMETHOD(PollForPotentialSupportedProperties)(THIS_ IUIAutomationElement *, SAFEARRAY **, SAFEARRAY **) PURE;
STDMETHOD(CheckNotSupported)(THIS_ VARIANT, BOOL *) PURE;
STDMETHOD(get_ReservedNotSupportedValue)(THIS_ IUnknown **) PURE;
STDMETHOD(get_ReservedMixedAttributeValue)(THIS_ IUnknown **) PURE;
STDMETHOD(ElementFromIAccessible)(THIS_ IAccessible *, int, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromIAccessibleBuildCache)(THIS_ IAccessible *, int, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationElement
DECLARE_INTERFACE_(IUIAutomationElement, IUnknown)
{
STDMETHOD(SetFocus)(THIS) PURE;
STDMETHOD(GetRuntimeId)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(FindFirst)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationElement **) PURE;
STDMETHOD(FindAll)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationElementArray **) PURE;
STDMETHOD(FindFirstBuildCache)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(FindAllBuildCache)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationCacheRequest *, IUIAutomationElementArray **) PURE;
STDMETHOD(BuildUpdatedCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetCurrentPropertyValue)(THIS_ PROPERTYID, VARIANT *) PURE;
STDMETHOD(GetCurrentPropertyValueEx)(THIS_ PROPERTYID, BOOL, VARIANT *) PURE;
STDMETHOD(GetCachedPropertyValue)(THIS_ PROPERTYID, VARIANT *) PURE;
STDMETHOD(GetCachedPropertyValueEx)(THIS_ PROPERTYID, BOOL, VARIANT *) PURE;
STDMETHOD(GetCurrentPatternAs)(THIS_ PATTERNID, REFIID, void **) PURE;
STDMETHOD(GetCachedPatternAs)(THIS_ PATTERNID, REFIID, void **) PURE;
STDMETHOD(GetCurrentPattern)(THIS_ PATTERNID, IUnknown **) PURE;
STDMETHOD(GetCachedPattern)(THIS_ PATTERNID, IUnknown **) PURE;
STDMETHOD(GetCachedParent)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetCachedChildren)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CurrentProcessId)(THIS_ int *) PURE;
STDMETHOD(get_CurrentControlType)(THIS_ CONTROLTYPEID *) PURE;
STDMETHOD(get_CurrentLocalizedControlType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAcceleratorKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAccessKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentHasKeyboardFocus)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsKeyboardFocusable)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsEnabled)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentAutomationId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentClassName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentHelpText)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentCulture)(THIS_ int *) PURE;
STDMETHOD(get_CurrentIsControlElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsContentElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsPassword)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentNativeWindowHandle)(THIS_ UIA_HWND *) PURE;
STDMETHOD(get_CurrentItemType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsOffscreen)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentOrientation)(THIS_ enum OrientationType *) PURE;
STDMETHOD(get_CurrentFrameworkId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsRequiredForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentItemStatus)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentBoundingRectangle)(THIS_ RECT *) PURE;
STDMETHOD(get_CurrentLabeledBy)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CurrentAriaRole)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAriaProperties)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsDataValidForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentControllerFor)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentDescribedBy)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentFlowsTo)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentProviderDescription)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedProcessId)(THIS_ int *) PURE;
STDMETHOD(get_CachedControlType)(THIS_ CONTROLTYPEID *) PURE;
STDMETHOD(get_CachedLocalizedControlType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAcceleratorKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAccessKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedHasKeyboardFocus)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsKeyboardFocusable)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsEnabled)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedAutomationId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedClassName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedHelpText)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedCulture)(THIS_ int *) PURE;
STDMETHOD(get_CachedIsControlElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsContentElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsPassword)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedNativeWindowHandle)(THIS_ UIA_HWND *) PURE;
STDMETHOD(get_CachedItemType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsOffscreen)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedOrientation)(THIS_ enum OrientationType *) PURE;
STDMETHOD(get_CachedFrameworkId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsRequiredForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedItemStatus)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedBoundingRectangle)(THIS_ RECT *) PURE;
STDMETHOD(get_CachedLabeledBy)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CachedAriaRole)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAriaProperties)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsDataValidForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedControllerFor)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedDescribedBy)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedFlowsTo)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedProviderDescription)(THIS_ BSTR *) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTextPattern
DECLARE_INTERFACE_(IUIAutomationTextPattern, IUnknown)
{
STDMETHOD(RangeFromPoint)(THIS_ POINT, IUIAutomationTextRange **) PURE;
STDMETHOD(RangeFromChild)(THIS_ IUIAutomationElement *, IUIAutomationTextRange **) PURE;
STDMETHOD(GetSelection)(THIS_ IUIAutomationTextRangeArray **) PURE;
STDMETHOD(GetVisibleRanges)(THIS_ IUIAutomationTextRangeArray **) PURE;
STDMETHOD(get_DocumentRange)(THIS_ IUIAutomationTextRange **) PURE;
STDMETHOD(get_SupportedTextSelection)(THIS_ enum SupportedTextSelection *) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTreeWalker
DECLARE_INTERFACE_(IUIAutomationTreeWalker, IUnknown)
{
STDMETHOD(GetParentElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetFirstChildElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetLastChildElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetNextSiblingElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetPreviousSiblingElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(NormalizeElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetParentElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetFirstChildElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetLastChildElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetNextSiblingElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetPreviousSiblingElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(NormalizeElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(get_Condition)(THIS_ IUIAutomationCondition **) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTextRange
DECLARE_INTERFACE_(IUIAutomationTextRange, IUnknown)
{
STDMETHOD(Clone)(THIS_ IUIAutomationTextRange **) PURE;
STDMETHOD(Compare)(THIS_ IUIAutomationTextRange *, BOOL *) PURE;
STDMETHOD(CompareEndpoints)(THIS_ enum TextPatternRangeEndpoint, IUIAutomationTextRange *, enum TextPatternRangeEndpoint, int *) PURE;
STDMETHOD(ExpandToEnclosingUnit)(THIS_ enum TextUnit) PURE;
STDMETHOD(FindAttribute)(THIS_ TEXTATTRIBUTEID, VARIANT, BOOL, IUIAutomationTextRange **) PURE;
STDMETHOD(FindText)(THIS_ BSTR, BOOL, BOOL, IUIAutomationTextRange **) PURE;
STDMETHOD(GetAttributeValue)(THIS_ TEXTATTRIBUTEID, VARIANT *) PURE;
STDMETHOD(GetBoundingRectangles)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(GetEnclosingElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetText)(THIS_ int, BSTR *) PURE;
STDMETHOD(Move)(THIS_ enum TextUnit, int, int *) PURE;
STDMETHOD(MoveEndpointByUnit)(THIS_ enum TextPatternRangeEndpoint, enum TextUnit, int *) PURE;
STDMETHOD(MoveEndpointByRange)(THIS_ enum TextPatternRangeEndpoint, IUIAutomationTextRange *, enum TextPatternRangeEndpoint) PURE;
STDMETHOD(Select)(THIS) PURE;
STDMETHOD(AddToSelection)(THIS) PURE;
STDMETHOD(RemoveFromSelection)(THIS) PURE;
STDMETHOD(ScrollIntoView)(THIS_ BOOL) PURE;
STDMETHOD(GetChildren)(THIS_ IUIAutomationElementArray **) PURE;
};
#undef INTERFACE
#ifdef __cplusplus
}
#endif
#endif // UIAUTO_HH

View file

@ -132,7 +132,7 @@ long decode( char const * in_, size_t inSize, wchar * out_ )
return out - out_;
}
string encode( wstring const & in ) throw()
string encode( wstring const & in ) noexcept
{
if( in.size() == 0 )
return string();

View file

@ -44,7 +44,7 @@ size_t encode( wchar const * in, size_t inSize, char * out );
long decode( char const * in, size_t inSize, wchar * out );
/// Versions for non time-critical code.
string encode( wstring const & ) throw();
string encode( wstring const & ) noexcept;
wstring decode( string const & ) ;
/// Since the standard isspace() is locale-specific, we need something

113
utils.hh
View file

@ -9,6 +9,8 @@
#include <QKeyEvent>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonObject>
#include <QJsonDocument>
namespace Utils
{
@ -26,6 +28,39 @@ inline QString rstrip(const QString &str) {
return "";
}
/**
* remove punctuation , space, symbol
*
*
* " abc, '" should be "abc"
*/
inline QString trimNonChar( const QString & str )
{
QString remain;
int n = str.size() - 1;
for( ; n >= 0; --n )
{
auto c = str.at( n );
if( !c.isSpace() && !c.isSymbol() && !c.isNonCharacter() && !c.isPunct()&& !c.isNull() )
{
remain = str.left( n + 1 );
break;
}
}
n = 0;
for( ; n < remain.size(); n++ )
{
auto c = remain.at( n );
if( !c.isSpace() && !c.isSymbol() && !c.isNonCharacter() && !c.isPunct() )
{
return remain.mid( n );
}
}
return "";
}
/**
* str="abc\r\n\u0000" should be returned as "abc"
* @brief rstripnull
@ -35,20 +70,14 @@ inline QString rstrip(const QString &str) {
inline QString rstripnull(const QString &str) {
int n = str.size() - 1;
for (; n >= 0; --n) {
if (!str.at(n).isSpace()&&!str.at(n).isNull()) {
auto c = str.at(n);
if (!c.isSpace()&&!c.isNull()) {
return str.left(n + 1);
}
}
return "";
}
inline QString unescapeHtml(const QString &str) {
QTextDocument text;
text.setHtml(str);
return text.toPlainText();
}
inline bool isExternalLink(QUrl const &url) {
return url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp" || url.scheme() == "mailto" ||
url.scheme() == "file" || url.toString().startsWith( "//" );
@ -77,6 +106,21 @@ inline bool ignoreKeyEvent(QKeyEvent *keyEvent) {
return false;
}
inline QString json2String( const QJsonObject & json )
{
return QString( QJsonDocument( json ).toJson( QJsonDocument::Compact ) );
}
inline QStringList repeat( const QString str, const int times )
{
QStringList list;
for( int i = 0; i < times; i++ )
{
list << str;
}
return list;
}
namespace AtomicInt
{
@ -89,6 +133,7 @@ inline int loadAcquire( QAtomicInt const & ref )
namespace Url
{
// This wrapper is created due to behavior change of the setPath() method
// See: https://bugreports.qt-project.org/browse/QTBUG-27728
// https://codereview.qt-project.org/#change,38257
@ -151,16 +196,15 @@ inline QString fragment( const QUrl & url )
return url.fragment( QUrl::FullyDecoded );
}
// extract query word from url
inline QString getWordFromUrl( const QUrl & url )
// get the query word of bword and gdlookup scheme.
// if the scheme is gdlookup or scheme ,the first value of pair is true,otherwise is false;
inline std::pair< bool, QString > getQueryWord( QUrl const & url )
{
QString word;
if( url.scheme().compare( "bword" ) == 0 )
{
word = url.path();
}
else if( url.scheme() == "gdlookup" ) // Plain html links inherit gdlookup scheme
bool validScheme = false;
if( url.scheme().compare( "gdlookup" ) == 0 )
{
validScheme = true;
if( hasQueryItem( url, "word" ) )
{
word = queryItemValue( url, "word" );
@ -170,8 +214,31 @@ inline QString getWordFromUrl( const QUrl & url )
word = url.path().mid( 1 );
}
}
if( url.scheme().compare( "bword" ) == 0 || url.scheme().compare( "entry" ) == 0 )
{
validScheme = true;
return word;
auto path = url.path();
// url like this , bword:word or bword://localhost/word
if( !path.isEmpty() )
{
//url,bword://localhost/word
if( path.startsWith( "/" ) )
word = path.mid( 1 );
else
word = path;
}
else
{
// url looks like this, bword://word,or bword://localhost
auto host = url.host();
if( host != "localhost" )
{
word = host;
}
}
}
return std::make_pair( validScheme, word );
}
}
@ -181,13 +248,6 @@ namespace
{
/// Uses some heuristics to chop off the first domain name from the host name,
/// but only if it's not too base. Returns the resulting host name.
inline QString getHostBase( QUrl const & url )
{
QString host = url.host();
return getHostBase(host);
}
inline QString getHostBase( QString const & host )
{
QStringList domains = host.split( '.' );
@ -212,6 +272,13 @@ inline QString getHostBase( QString const & host )
else
return host;
}
inline QString getHostBaseFromUrl( QUrl const & url )
{
QString host = url.host();
return getHostBase( host );
}
}
#endif // UTILS_HH

View file

@ -44,16 +44,16 @@ public:
{
}
virtual string getName() throw()
virtual string getName() noexcept
{ return voiceEngine.name.toUtf8().data(); }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const & word,
@ -67,7 +67,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
sptr< WordSearchRequest > VoiceEnginesDictionary::prefixMatch( wstring const & /*word*/,
@ -110,7 +110,7 @@ sptr< Dictionary::DataRequest > VoiceEnginesDictionary::getArticle(
return ret;
}
void VoiceEnginesDictionary::loadIcon() throw()
void VoiceEnginesDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -53,16 +53,16 @@ public:
dictionaryDescription = temp;
}
virtual string getName() throw()
virtual string getName() noexcept
{ return name; }
virtual map< Property, string > getProperties() throw()
virtual map< Property, string > getProperties() noexcept
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return 0; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return 0; }
virtual sptr< WordSearchRequest > prefixMatch( wstring const & word,
@ -79,7 +79,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
sptr< WordSearchRequest > WebSiteDictionary::prefixMatch( wstring const & /*word*/,
@ -526,7 +526,7 @@ sptr< Dictionary::DataRequest > WebSiteDictionary::getResource( string const & n
return new WebSiteResourceRequest( link, netMgr, this );
}
void WebSiteDictionary::loadIcon() throw()
void WebSiteDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

View file

@ -1,114 +0,0 @@
#include <windows.h>
#include <servprov.h>
#include "wordbyauto.hh"
#include "uiauto.hh"
#include <cstdio>
#include "gddebug.hh"
class GDAutomationClient {
public:
GDAutomationClient();
~GDAutomationClient();
bool getWordAtPoint( POINT pt );
WCHAR *getText() { return buffer; }
private:
WCHAR buffer[256];
IUIAutomation *pGDAutomation;
IUIAutomationTreeWalker *pTree;
};
GDAutomationClient gdAuto;
GDAutomationClient::GDAutomationClient()
{
HRESULT hr;
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
hr = CoCreateInstance( CLSID_CUIAutomation , NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, (void**)&pGDAutomation );
if( hr != S_OK ) pGDAutomation = NULL;
pTree = NULL;
if( pGDAutomation != NULL )
hr = pGDAutomation->get_RawViewWalker( &pTree );
memset( buffer, 0, sizeof(buffer) );
}
GDAutomationClient::~GDAutomationClient()
{
if( pTree != NULL ) pTree->Release();
if( pGDAutomation != NULL ) pGDAutomation->Release();
CoUninitialize();
}
bool GDAutomationClient::getWordAtPoint( POINT pt )
{
HRESULT hr;
IUIAutomationTextPattern *pTextPattern;
IUIAutomationTextRange *pTextRange;
IUIAutomationElement *pElement, *pParent;
BSTR bstr;
RECT r = { 0, 0, 0, 0 };
bool bGoUp;
GD_DPRINTF("\nEntering getWordAtPoint\n");
if( pGDAutomation == NULL ) return false;
buffer[0] = 0;
pElement = NULL;
hr = pGDAutomation->ElementFromPoint( pt, &pElement );
GD_DPRINTF("ElementFromPoint return hr=%08lX, ptr=%p\n", hr, pElement);
if( hr != S_OK || pElement == NULL )
return false;
pTextPattern = NULL;
bGoUp = false;
while( pElement != NULL ) {
hr = pElement->GetCurrentPatternAs( UIA_TextPatternId, IID_IUIAutomationTextPattern, (void**)&pTextPattern );
if( hr == S_OK && pTextPattern != NULL )
break;
if( pTree == NULL ) {
pElement->Release();
return false;
}
pParent = NULL;
hr = pTree->GetParentElement( pElement, &pParent );
pElement->Release();
pElement = pParent;
bGoUp = TRUE;
}
if( pElement == NULL )
return false;
if( !bGoUp ) {
hr = pElement->get_CurrentBoundingRectangle( &r );
if( hr == S_OK) {
pt.x -= r.left;
pt.y -= r.top;
}
}
pElement->Release();
pTextRange = NULL;
hr = pTextPattern->RangeFromPoint( pt, &pTextRange );
pTextPattern->Release();
if( hr != S_OK || pTextRange == NULL )
return false;
hr = pTextRange->ExpandToEnclosingUnit( TextUnit_Word );
if( hr == S_OK) {
hr = pTextRange->GetText( 255, &bstr );
if (hr == S_OK) {
wsprintfW( buffer, L"%s", (LPCWSTR)bstr );
SysFreeString( bstr );
}
}
pTextRange->Release();
return ( buffer[0] != 0 );
}
WCHAR *gdGetWordAtPointByAutomation( POINT pt )
{
if( gdAuto.getWordAtPoint( pt ) ) return gdAuto.getText();
else return NULL;
}

View file

@ -1,6 +0,0 @@
#ifndef __WORD_BY_AUTO_HH_INCLUDED
#define __WORD_BY_AUTO_HH_INCLUDED
WCHAR *gdGetWordAtPointByAutomation( POINT pt );
#endif

12
xdxf.cc
View file

@ -147,16 +147,16 @@ public:
~XdxfDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -200,7 +200,7 @@ public:
protected:
void loadIcon() throw();
void loadIcon() noexcept;
private:
@ -312,7 +312,7 @@ XdxfDictionary::~XdxfDictionary()
dict_data_close( dz );
}
void XdxfDictionary::loadIcon() throw()
void XdxfDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;

266
zim.cc
View file

@ -78,7 +78,8 @@ enum CompressionType
struct ZIM_header
{
quint32 magicNumber;
quint32 version;
quint16 majorVersion;
quint16 minorVersion;
quint8 uuid[ 16 ];
quint32 articleCount;
quint32 clusterCount;
@ -125,7 +126,7 @@ __attribute__((packed))
enum
{
Signature = 0x584D495A, // ZIMX on little-endian, XMIZ on big-endian
CurrentFormatVersion = 1 + BtreeIndexing::FormatVersion + Folding::Version
CurrentFormatVersion = 3 + BtreeIndexing::FormatVersion + Folding::Version
};
struct IdxHeader
@ -158,13 +159,15 @@ struct Cache
quint32 clusterNumber;
int stamp;
int count, size;
unsigned blobs_offset_size;
Cache() :
data( 0 ),
clusterNumber( 0 ),
stamp( -1 ),
count( 0 ),
size( 0 )
size( 0 ),
blobs_offset_size( 0 )
{}
};
@ -184,13 +187,25 @@ public:
}
const ZIM_header & header() const
{ return zimHeader; }
string getClusterData( quint32 cluster_nom );
string getClusterData( quint32 cluster_nom, unsigned & blob_offset_size );
const QString getMimeType( quint16 nom )
{ return mimeTypes.value( nom ); }
bool isArticleMime( quint16 mime_type )
{ return getMimeType( mime_type ).startsWith( "text/html", Qt::CaseInsensitive )
|| getMimeType( mime_type ).startsWith( "text/plain", Qt::CaseInsensitive ); }
quint16 redirectedMimeType( RedirectEntry const & redEntry );
private:
ZIM_header zimHeader;
Cache cache[ CACHE_SIZE ];
int stamp;
QVector< QPair< quint64, quint32 > > clusterOffsets;
QStringList mimeTypes;
void clearCache();
};
@ -291,10 +306,33 @@ bool ZimFile::open()
std::sort( clusterOffsets.begin(), clusterOffsets.end() );
// Read mime types
string type;
char ch;
seek( zimHeader.mimeListPos );
for( ; ; )
{
type.clear();
while( getChar( &ch ) )
{
if( ch == 0 )
break;
type.push_back( ch );
}
if( type.empty() )
break;
QString s = QString::fromUtf8( type.c_str(), type.size() );
mimeTypes.append( s );
}
return true;
}
string ZimFile::getClusterData( quint32 cluster_nom )
string ZimFile::getClusterData( quint32 cluster_nom, unsigned & blobs_offset_size )
{
// Check cache
int target = 0;
@ -328,6 +366,7 @@ string ZimFile::getClusterData( quint32 cluster_nom )
if( found )
{
// Cache hit
blobs_offset_size = cache[ target ].blobs_offset_size;
return string( cache[ target ].data, cache[ target ].count );
}
@ -353,9 +392,11 @@ string ZimFile::getClusterData( quint32 cluster_nom )
seek( clusterOffsets.at( nom ).first );
char compressionType;
if( !getChar( &compressionType ) )
char compressionType, cluster_info;
if( !getChar( &cluster_info ) )
return string();
compressionType = cluster_info & 0x0F;
blobs_offset_size = cluster_info & 0x10 && zimHeader.majorVersion >= 6 ? 8 : 4;
string decompressedData;
@ -384,9 +425,16 @@ string ZimFile::getClusterData( quint32 cluster_nom )
// Check BLOBs number in the cluster
// We cache multi-element clusters only
quint32 firstOffset;
memcpy( &firstOffset, decompressedData.data(), sizeof(firstOffset) );
quint32 blobCount = ( firstOffset - 4 ) / 4;
quint32 firstOffset32;
quint64 firstOffset;
if( blobs_offset_size == 8 )
memcpy( &firstOffset, decompressedData.data(), sizeof(firstOffset) );
else
{
memcpy( &firstOffset32, decompressedData.data(), sizeof(firstOffset32) );
firstOffset = firstOffset32;
}
quint32 blobCount = ( firstOffset - blobs_offset_size ) / blobs_offset_size;
if( blobCount > 1 )
{
@ -410,12 +458,52 @@ string ZimFile::getClusterData( quint32 cluster_nom )
memcpy( cache[ target ].data, decompressedData.c_str(), size );
cache[ target ].count = size;
cache[ target ].clusterNumber = cluster_nom;
cache[ target ].blobs_offset_size = blobs_offset_size;
}
}
return decompressedData;
}
quint16 ZimFile::redirectedMimeType( RedirectEntry const & redEntry )
{
RedirectEntry current_entry = redEntry;
quint64 current_pos = pos();
quint16 mimetype = 0xFFFF;
for( ; ; )
{
quint32 current_nom = current_entry.redirectIndex;
seek( zimHeader.urlPtrPos + (quint64)current_nom * 8 );
quint64 new_pos;
if( read( reinterpret_cast< char * >( &new_pos ), sizeof(new_pos) ) != sizeof(new_pos) )
break;
seek( new_pos );
quint16 new_mimetype;
if( read( reinterpret_cast< char * >( &new_mimetype ), sizeof(new_mimetype) ) != sizeof(new_mimetype) )
break;
if( new_mimetype == 0xFFFF ) // Redirect to other article
{
if( read( reinterpret_cast< char * >( &current_entry ) + 2, sizeof( current_entry ) - 2 ) != sizeof( current_entry ) - 2 )
break;
if( current_nom == current_entry.redirectIndex )
break;
}
else
{
mimetype = new_mimetype;
break;
}
}
seek( current_pos );
return mimetype;
}
// Some supporting functions
bool indexIsOldOrBad( string const & indexFile )
@ -516,23 +604,42 @@ quint32 readArticle( ZimFile & file, quint32 articleNumber, string & result,
// Read cluster data
string decompressedData = file.getClusterData( artEntry.clusterNumber );
unsigned offset_size = 0;
string decompressedData = file.getClusterData( artEntry.clusterNumber, offset_size );
if( decompressedData.empty() )
break;
// Take article data from cluster
quint32 firstOffset;
memcpy( &firstOffset, decompressedData.data(), sizeof(firstOffset) );
quint32 blobCount = ( firstOffset - 4 ) / 4;
quint32 firstOffset32;
quint64 firstOffset;
if( offset_size == 8 )
memcpy( &firstOffset, decompressedData.data(), sizeof(firstOffset) );
else
{
memcpy( &firstOffset32, decompressedData.data(), sizeof(firstOffset32) );
firstOffset = firstOffset32;
}
quint32 blobCount = ( firstOffset - offset_size ) / offset_size;
if( artEntry.blobNumber > blobCount )
break;
quint32 offsets[ 2 ];
memcpy( offsets, decompressedData.data() + artEntry.blobNumber * 4, sizeof(offsets) );
quint32 size = offsets[ 1 ] - offsets[ 0 ];
result.append( decompressedData, offsets[ 0 ], size );
quint32 size;
if( offset_size == 8 )
{
quint64 offsets[ 2 ];
memcpy( offsets, decompressedData.data() + artEntry.blobNumber * 8, sizeof(offsets) );
size = offsets[ 1 ] - offsets[ 0 ];
result.append( decompressedData, offsets[ 0 ], size );
}
else
{
quint32 offsets[ 2 ];
memcpy( offsets, decompressedData.data() + artEntry.blobNumber * 4, sizeof(offsets) );
size = offsets[ 1 ] - offsets[ 0 ];
result.append( decompressedData, offsets[ 0 ], size );
}
return articleNumber;
}
@ -562,16 +669,16 @@ class ZimDictionary: public BtreeIndexing::BtreeDictionary
~ZimDictionary();
virtual string getName() throw()
virtual string getName() noexcept
{ return dictionaryName; }
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.articleCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return idxHeader.wordCount; }
inline virtual quint32 getLangFrom() const
@ -618,7 +725,7 @@ class ZimDictionary: public BtreeIndexing::BtreeDictionary
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
private:
@ -662,7 +769,7 @@ ZimDictionary::ZimDictionary( string const & id,
{
QString name = QDir::fromNativeSeparators( FsEncoding::decode( dictionaryFiles[ 0 ].c_str() ) );
int n = name.lastIndexOf( '/' );
dictionaryName = string( name.mid( n + 1 ).toUtf8().constData() );
dictionaryName = name.mid( n + 1 ).toStdString();
}
else
{
@ -685,7 +792,7 @@ ZimDictionary::~ZimDictionary()
df.close();
}
void ZimDictionary::loadIcon() throw()
void ZimDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;
@ -1132,32 +1239,8 @@ sptr< Dictionary::DataRequest > ZimDictionary::getSearchResults( QString const &
/// ZimDictionary::getArticle()
class ZimArticleRequest;
class ZimArticleRequestRunnable: public QRunnable
{
ZimArticleRequest & r;
QSemaphore & hasExited;
public:
ZimArticleRequestRunnable( ZimArticleRequest & r_,
QSemaphore & hasExited_ ): r( r_ ),
hasExited( hasExited_ )
{}
~ZimArticleRequestRunnable()
{
hasExited.release();
}
virtual void run();
};
class ZimArticleRequest: public Dictionary::DataRequest
{
friend class ZimArticleRequestRunnable;
wstring word;
vector< wstring > alts;
ZimDictionary & dict;
@ -1173,11 +1256,10 @@ public:
ZimDictionary & dict_, bool ignoreDiacritics_ ):
word( word_ ), alts( alts_ ), dict( dict_ ), ignoreDiacritics( ignoreDiacritics_ )
{
QThreadPool::globalInstance()->start(
new ZimArticleRequestRunnable( *this, hasExited ) );
QThreadPool::globalInstance()->start( [ this ]() { this->run(); } );
}
void run(); // Run from another thread by ZimArticleRequestRunnable
void run();
virtual void cancel()
{
@ -1191,11 +1273,6 @@ public:
}
};
void ZimArticleRequestRunnable::run()
{
r.run();
}
void ZimArticleRequest::run()
{
if ( Utils::AtomicInt::loadAcquire( isCancelled ) )
@ -1336,32 +1413,8 @@ sptr< Dictionary::DataRequest > ZimDictionary::getArticle( wstring const & word,
//// ZimDictionary::getResource()
class ZimResourceRequest;
class ZimResourceRequestRunnable: public QRunnable
{
ZimResourceRequest & r;
QSemaphore & hasExited;
public:
ZimResourceRequestRunnable( ZimResourceRequest & r_,
QSemaphore & hasExited_ ): r( r_ ),
hasExited( hasExited_ )
{}
~ZimResourceRequestRunnable()
{
//hasExited.release();
}
virtual void run();
};
class ZimResourceRequest: public Dictionary::DataRequest
{
friend class ZimResourceRequestRunnable;
ZimDictionary & dict;
string resourceName;
@ -1372,12 +1425,10 @@ class ZimResourceRequest: public Dictionary::DataRequest
public:
ZimResourceRequest(ZimDictionary &dict_, string const &resourceName_)
: dict(dict_), resourceName(resourceName_) {
//(new ZimResourceRequestRunnable(*this, hasExited))->run();
QThreadPool::globalInstance()->start(
new ZimResourceRequestRunnable( *this, hasExited ) );
QThreadPool::globalInstance()->start( [ this ]() { this->run(); } );
}
void run(); // Run from another thread by ZimResourceRequestRunnable
void run();
virtual void cancel()
{
@ -1391,11 +1442,6 @@ public:
}
};
void ZimResourceRequestRunnable::run()
{
r.run();
}
void ZimResourceRequest::run()
{
// Some runnables linger enough that they are cancelled before they start
@ -1498,6 +1544,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
df.open();
ZIM_header const & zh = df.header();
bool new_namespaces = ( zh.majorVersion >= 6 && zh.minorVersion >= 1 );
if( zh.magicNumber != 0x44D495A )
throw exNotZimFile( i->c_str() );
@ -1534,7 +1581,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
}
const quint64 * ptr;
quint16 mimetype;
quint16 mimetype, redirected_mime = 0xFFFF;
ArticleEntry artEntry;
RedirectEntry redEntry;
string url, title;
@ -1551,6 +1598,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
if( ret != sizeof(RedirectEntry) - 2 )
throw exCantReadFile( i->c_str() );
redirected_mime = df.redirectedMimeType( redEntry );
nameSpace = redEntry.nameSpace;
}
else
@ -1562,7 +1610,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
nameSpace = artEntry.nameSpace;
if( nameSpace == 'A' )
if( ( nameSpace == 'A' || ( nameSpace == 'C' && new_namespaces ) ) && df.isArticleMime( mimetype ) )
articleCount++;
}
@ -1585,7 +1633,8 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
title.push_back( ch );
}
if( nameSpace == 'A' )
if( nameSpace == 'A' || ( nameSpace == 'C' && new_namespaces && ( df.isArticleMime( mimetype )
|| ( mimetype == 0xFFFF && df.isArticleMime( redirected_mime ) ) ) ) )
{
wstring word;
if( !title.empty() )
@ -1593,16 +1642,26 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
else
word = Utf8::decode( url );
if( maxHeadwordsToExpand && zh.articleCount >= maxHeadwordsToExpand )
indexedWords.addSingleWord( word, n );
if( df.isArticleMime( mimetype )
|| ( mimetype == 0xFFFF && df.isArticleMime( redirected_mime ) ) )
{
if( maxHeadwordsToExpand && zh.articleCount >= maxHeadwordsToExpand )
indexedWords.addSingleWord( word, n );
else
indexedWords.addWord( word, n );
wordCount++;
}
else
indexedWords.addWord( word, n );
wordCount++;
{
url.insert( url.begin(), '/' );
url.insert( url.begin(), nameSpace );
indexedResources.addSingleWord( Utf8::decode( url ), n );
}
}
else
if( nameSpace == 'M' )
{
if( url.compare( "Title") == 0 )
if( url.compare( "Title" ) == 0 )
{
idxHeader.namePtr = n;
string name;
@ -1610,10 +1669,10 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
initializing.indexingDictionary( name );
}
else
if( url.compare( "Description") == 0 )
if( url.compare( "Description" ) == 0 )
idxHeader.descriptionPtr = n;
else
if( url.compare( "Language") == 0 )
if( url.compare( "Language" ) == 0 )
{
string lang;
readArticle( df, n, lang );
@ -1626,6 +1685,11 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
}
}
else
if( nameSpace == 'X' )
{
continue;
}
else
{
url.insert( url.begin(), '/' );
url.insert( url.begin(), nameSpace );

View file

@ -114,15 +114,15 @@ public:
ZipSoundsDictionary( string const & id, string const & indexFile,
vector< string > const & dictionaryFiles );
virtual string getName() throw();
virtual string getName() noexcept;
virtual map< Dictionary::Property, string > getProperties() throw()
virtual map< Dictionary::Property, string > getProperties() noexcept
{ return map< Dictionary::Property, string >(); }
virtual unsigned long getArticleCount() throw()
virtual unsigned long getArticleCount() noexcept
{ return idxHeader.soundsCount; }
virtual unsigned long getWordCount() throw()
virtual unsigned long getWordCount() noexcept
{ return getArticleCount(); }
virtual sptr< Dictionary::DataRequest > getArticle( wstring const &,
@ -136,7 +136,7 @@ public:
protected:
virtual void loadIcon() throw();
virtual void loadIcon() noexcept;
};
ZipSoundsDictionary::ZipSoundsDictionary( string const & id,
@ -164,7 +164,7 @@ ZipSoundsDictionary::ZipSoundsDictionary( string const & id,
}
string ZipSoundsDictionary::getName() throw()
string ZipSoundsDictionary::getName() noexcept
{
string result = FsEncoding::basename( getDictionaryFilenames()[ 0 ] );
@ -384,7 +384,7 @@ sptr< Dictionary::DataRequest > ZipSoundsDictionary::getResource( string const &
return new Dictionary::DataRequestInstant( false );
}
void ZipSoundsDictionary::loadIcon() throw()
void ZipSoundsDictionary::loadIcon() noexcept
{
if ( dictionaryIconLoaded )
return;