mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 15:24:05 +00:00
Compare commits
23 commits
2d0a5752c1
...
677745ba09
Author | SHA1 | Date | |
---|---|---|---|
677745ba09 | |||
8fd5b37335 | |||
4758f9e972 | |||
608016208b | |||
1e3b22ebd0 | |||
720f66c781 | |||
acbfef0870 | |||
d4db51f278 | |||
6c63ba45b6 | |||
a9478cdc34 | |||
c0697ecdda | |||
701a4effb3 | |||
f9a3705942 | |||
2c91b78e13 | |||
c6387df392 | |||
43c982cf8a | |||
e07e730a09 | |||
ab214cfb05 | |||
c00239a1b1 | |||
469896bbf1 | |||
0d89c4ab56 | |||
9e99389cc3 | |||
6edfd15962 |
|
@ -17,7 +17,6 @@ Checks: >
|
||||||
portability-*,
|
portability-*,
|
||||||
readability-*,
|
readability-*,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-bugprone-reserved-identifier,
|
|
||||||
-cppcoreguidelines-owning-memory,
|
-cppcoreguidelines-owning-memory,
|
||||||
-cppcoreguidelines-prefer-member-initializer,
|
-cppcoreguidelines-prefer-member-initializer,
|
||||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
@ -26,6 +25,7 @@ Checks: >
|
||||||
-google-default-arguments,
|
-google-default-arguments,
|
||||||
-google-readability-casting,
|
-google-readability-casting,
|
||||||
-hicpp-deprecated-headers,
|
-hicpp-deprecated-headers,
|
||||||
|
-hicpp-no-array-decay,
|
||||||
-misc-const-correctness,
|
-misc-const-correctness,
|
||||||
-misc-include-cleaner,
|
-misc-include-cleaner,
|
||||||
-misc-non-private-member-variables-in-classes,
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
@ -43,5 +43,11 @@ CheckOptions:
|
||||||
value: 1
|
value: 1
|
||||||
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||||
value: 1
|
value: 1
|
||||||
|
- key: modernize-avoid-c-arrays.AllowStringArrays
|
||||||
|
value: 1
|
||||||
|
- key: cppcoreguidelines-avoid-c-arrays.AllowStringArrays
|
||||||
|
value: 1
|
||||||
|
- key: hicpp-avoid-c-arrays.AllowStringArrays
|
||||||
|
value: 1
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
|
@ -529,6 +529,26 @@ void ArticleRequest::altSearchFinished()
|
||||||
|
|
||||||
for ( const auto & activeDict : activeDicts ) {
|
for ( const auto & activeDict : activeDicts ) {
|
||||||
try {
|
try {
|
||||||
|
// if the dictionary is website dictionary and openinNewTab is enabled, emit a signal.
|
||||||
|
if ( GlobalBroadcaster::instance()->getPreference()->openWebsiteInNewTab ) {
|
||||||
|
if ( ( activeDict->getFeatures() | Dictionary::WebSite ) == Dictionary::WebSite ) {
|
||||||
|
//replace the word,and get the actual requested url
|
||||||
|
string url = activeDict->getProperties()[ Dictionary::Property::Url ];
|
||||||
|
if ( url.empty() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString requestUrl = Utils::WebSite::urlReplaceWord( QString::fromStdString( url ), word );
|
||||||
|
emit GlobalBroadcaster::instance()
|
||||||
|
-> websiteDictionarySignal( QString::fromStdString( activeDict->getName() ), requestUrl );
|
||||||
|
QStringList dictIds;
|
||||||
|
dictIds << QString::fromStdString( activeDict->getId() );
|
||||||
|
ActiveDictIds hittedWord{ group.id, word, dictIds };
|
||||||
|
emit GlobalBroadcaster::instance() -> dictionaryChanges( hittedWord );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sptr< Dictionary::DataRequest > r = activeDict->getArticle(
|
sptr< Dictionary::DataRequest > r = activeDict->getArticle(
|
||||||
wordStd,
|
wordStd,
|
||||||
altsVector,
|
altsVector,
|
||||||
|
|
|
@ -4,22 +4,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
/// A way to declare an exception class fast
|
/// A way to declare an exception class fast
|
||||||
/// Do like this:
|
/// Do like this:
|
||||||
/// DEF_EX( exErrorInFoo, "An error in foo encountered", std::exception )
|
/// DEF_EX( exErrorInFoo, "An error in foo encountered", std::exception )
|
||||||
/// DEF_EX( exFooNotFound, "Foo was not found", exErrorInFoo )
|
/// DEF_EX( exFooNotFound, "Foo was not found", exErrorInFoo )
|
||||||
|
#define DEF_EX( exName, exDescription, exParent ) \
|
||||||
#define DEF_EX( exName, exDescription, exParent ) \
|
constexpr static char ExStr_## exName[] = exDescription; \
|
||||||
class exName: public exParent \
|
using exName = defineEx< exParent, ExStr_## exName >;
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
virtual const char * what() const noexcept \
|
|
||||||
{ \
|
|
||||||
return ( exDescription ); \
|
|
||||||
} \
|
|
||||||
virtual ~exName() noexcept {} \
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
|
/// Same as DEF_EX, but takes a runtime string argument, which gets concatenated
|
||||||
/// with the description.
|
/// with the description.
|
||||||
|
@ -29,20 +24,36 @@
|
||||||
/// throw exCantOpen( "example.txt" );
|
/// throw exCantOpen( "example.txt" );
|
||||||
///
|
///
|
||||||
/// what() would return "can't open file example.txt"
|
/// what() would return "can't open file example.txt"
|
||||||
|
///
|
||||||
|
#define DEF_EX_STR( exName, exDescription, exParent ) \
|
||||||
|
constexpr static char ExStr_## exName[] = exDescription; \
|
||||||
|
using exName = defineExStr< exParent, ExStr_## exName >;
|
||||||
|
|
||||||
#define DEF_EX_STR( exName, exDescription, exParent ) \
|
// clang-format on
|
||||||
class exName: public exParent \
|
|
||||||
{ \
|
template< typename ParentEx, const char * description >
|
||||||
std::string value; \
|
class defineEx: public ParentEx
|
||||||
\
|
{
|
||||||
public: \
|
public:
|
||||||
explicit exName( std::string const & value_ ): \
|
virtual const char * what() const noexcept
|
||||||
value( std::string( exDescription ) + " " + value_ ) \
|
{
|
||||||
{ \
|
return description;
|
||||||
} \
|
}
|
||||||
virtual const char * what() const noexcept \
|
};
|
||||||
{ \
|
|
||||||
return value.c_str(); \
|
template< typename ParentEx, const char * description >
|
||||||
} \
|
class defineExStr: public ParentEx
|
||||||
virtual ~exName() noexcept {} \
|
{
|
||||||
};
|
public:
|
||||||
|
explicit defineExStr( std::string const & message_ ):
|
||||||
|
message( fmt::format( "{} {}", description, message_ ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual const char * what() const noexcept
|
||||||
|
{
|
||||||
|
return message.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
|
@ -45,4 +45,6 @@ signals:
|
||||||
void dictionaryClear( ActiveDictIds ad );
|
void dictionaryClear( ActiveDictIds ad );
|
||||||
|
|
||||||
void indexingDictionary( QString );
|
void indexingDictionary( QString );
|
||||||
|
|
||||||
|
void websiteDictionarySignal( QString, QString );
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,9 +197,6 @@ Preferences::Preferences():
|
||||||
hideSingleTab( false ),
|
hideSingleTab( false ),
|
||||||
mruTabOrder( false ),
|
mruTabOrder( false ),
|
||||||
hideMenubar( false ),
|
hideMenubar( false ),
|
||||||
enableTrayIcon( true ),
|
|
||||||
startToTray( false ),
|
|
||||||
closeToTray( true ),
|
|
||||||
autoStart( false ),
|
autoStart( false ),
|
||||||
doubleClickTranslates( true ),
|
doubleClickTranslates( true ),
|
||||||
selectWordBySingleClick( false ),
|
selectWordBySingleClick( false ),
|
||||||
|
@ -903,10 +900,11 @@ Class load()
|
||||||
c.preferences.hideSingleTab = ( preferences.namedItem( "hideSingleTab" ).toElement().text() == "1" );
|
c.preferences.hideSingleTab = ( preferences.namedItem( "hideSingleTab" ).toElement().text() == "1" );
|
||||||
c.preferences.mruTabOrder = ( preferences.namedItem( "mruTabOrder" ).toElement().text() == "1" );
|
c.preferences.mruTabOrder = ( preferences.namedItem( "mruTabOrder" ).toElement().text() == "1" );
|
||||||
c.preferences.hideMenubar = ( preferences.namedItem( "hideMenubar" ).toElement().text() == "1" );
|
c.preferences.hideMenubar = ( preferences.namedItem( "hideMenubar" ).toElement().text() == "1" );
|
||||||
|
#ifndef Q_OS_MACOS // // macOS uses the dock menu instead of the tray icon
|
||||||
c.preferences.enableTrayIcon = ( preferences.namedItem( "enableTrayIcon" ).toElement().text() == "1" );
|
c.preferences.enableTrayIcon = ( preferences.namedItem( "enableTrayIcon" ).toElement().text() == "1" );
|
||||||
c.preferences.startToTray = ( preferences.namedItem( "startToTray" ).toElement().text() == "1" );
|
c.preferences.startToTray = ( preferences.namedItem( "startToTray" ).toElement().text() == "1" );
|
||||||
c.preferences.closeToTray = ( preferences.namedItem( "closeToTray" ).toElement().text() == "1" );
|
c.preferences.closeToTray = ( preferences.namedItem( "closeToTray" ).toElement().text() == "1" );
|
||||||
|
#endif
|
||||||
c.preferences.autoStart = ( preferences.namedItem( "autoStart" ).toElement().text() == "1" );
|
c.preferences.autoStart = ( preferences.namedItem( "autoStart" ).toElement().text() == "1" );
|
||||||
c.preferences.alwaysOnTop = ( preferences.namedItem( "alwaysOnTop" ).toElement().text() == "1" );
|
c.preferences.alwaysOnTop = ( preferences.namedItem( "alwaysOnTop" ).toElement().text() == "1" );
|
||||||
c.preferences.searchInDock = ( preferences.namedItem( "searchInDock" ).toElement().text() == "1" );
|
c.preferences.searchInDock = ( preferences.namedItem( "searchInDock" ).toElement().text() == "1" );
|
||||||
|
@ -1073,6 +1071,10 @@ Class load()
|
||||||
( preferences.namedItem( "removeInvalidIndexOnExit" ).toElement().text() == "1" );
|
( preferences.namedItem( "removeInvalidIndexOnExit" ).toElement().text() == "1" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !preferences.namedItem( "openWebsiteInNewTab" ).isNull() ) {
|
||||||
|
c.preferences.openWebsiteInNewTab = ( preferences.namedItem( "openWebsiteInNewTab" ).toElement().text() == "1" );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !preferences.namedItem( "maxStringsInHistory" ).isNull() ) {
|
if ( !preferences.namedItem( "maxStringsInHistory" ).isNull() ) {
|
||||||
c.preferences.maxStringsInHistory = preferences.namedItem( "maxStringsInHistory" ).toElement().text().toUInt();
|
c.preferences.maxStringsInHistory = preferences.namedItem( "maxStringsInHistory" ).toElement().text().toUInt();
|
||||||
}
|
}
|
||||||
|
@ -2102,6 +2104,10 @@ void save( Class const & c )
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.removeInvalidIndexOnExit ? "1" : "0" ) );
|
opt.appendChild( dd.createTextNode( c.preferences.removeInvalidIndexOnExit ? "1" : "0" ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
|
opt = dd.createElement( "openWebsiteInNewTab" );
|
||||||
|
opt.appendChild( dd.createTextNode( c.preferences.openWebsiteInNewTab ? "1" : "0" ) );
|
||||||
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
opt = dd.createElement( "maxStringsInHistory" );
|
opt = dd.createElement( "maxStringsInHistory" );
|
||||||
opt.appendChild( dd.createTextNode( QString::number( c.preferences.maxStringsInHistory ) ) );
|
opt.appendChild( dd.createTextNode( QString::number( c.preferences.maxStringsInHistory ) ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
|
@ -341,9 +341,17 @@ struct Preferences
|
||||||
bool hideSingleTab;
|
bool hideSingleTab;
|
||||||
bool mruTabOrder;
|
bool mruTabOrder;
|
||||||
bool hideMenubar;
|
bool hideMenubar;
|
||||||
bool enableTrayIcon;
|
|
||||||
bool startToTray;
|
#ifdef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
bool closeToTray;
|
bool closeToTray = false;
|
||||||
|
bool enableTrayIcon = false;
|
||||||
|
bool startToTray = false;
|
||||||
|
#else
|
||||||
|
bool enableTrayIcon = true;
|
||||||
|
bool closeToTray = true;
|
||||||
|
bool startToTray = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool autoStart;
|
bool autoStart;
|
||||||
bool doubleClickTranslates;
|
bool doubleClickTranslates;
|
||||||
bool selectWordBySingleClick;
|
bool selectWordBySingleClick;
|
||||||
|
@ -392,6 +400,7 @@ struct Preferences
|
||||||
int maxNetworkCacheSize;
|
int maxNetworkCacheSize;
|
||||||
bool clearNetworkCacheOnExit;
|
bool clearNetworkCacheOnExit;
|
||||||
bool removeInvalidIndexOnExit = false;
|
bool removeInvalidIndexOnExit = false;
|
||||||
|
bool openWebsiteInNewTab = false;
|
||||||
|
|
||||||
qreal zoomFactor;
|
qreal zoomFactor;
|
||||||
qreal helpZoomFactor;
|
qreal helpZoomFactor;
|
||||||
|
|
|
@ -46,10 +46,6 @@ using BtreeIndexing::IndexInfo;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
DEF_EX_STR( exNotAardFile, "Not an AARD file", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exWordIsTooLarge, "Enountered a word that is too large:", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exSuddenEndOfFile, "Sudden end of file", Dictionary::Ex )
|
|
||||||
|
|
||||||
#pragma pack( push, 1 )
|
#pragma pack( push, 1 )
|
||||||
|
|
||||||
/// AAR file header
|
/// AAR file header
|
||||||
|
|
|
@ -169,10 +169,6 @@ void addEntryToIndex( string & word,
|
||||||
indexedWords.addWord( Utf8::decode( word ), articleOffset );
|
indexedWords.addWord( Utf8::decode( word ), articleOffset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEF_EX( exFailedToDecompressArticle, "Failed to decompress article's body", Dictionary::Ex )
|
|
||||||
DEF_EX( exChunkIndexOutOfRange, "Chunk index is out of range", Dictionary::Ex )
|
|
||||||
|
|
||||||
class BglDictionary: public BtreeIndexing::BtreeDictionary
|
class BglDictionary: public BtreeIndexing::BtreeDictionary
|
||||||
{
|
{
|
||||||
QMutex idxMutex;
|
QMutex idxMutex;
|
||||||
|
|
|
@ -34,7 +34,8 @@ enum Property {
|
||||||
Author,
|
Author,
|
||||||
Copyright,
|
Copyright,
|
||||||
Description,
|
Description,
|
||||||
Email
|
Email,
|
||||||
|
Url,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF_EX( Ex, "Dictionary error", std::exception )
|
DEF_EX( Ex, "Dictionary error", std::exception )
|
||||||
|
|
|
@ -301,7 +301,6 @@ namespace {
|
||||||
////////////////// GLS Dictionary
|
////////////////// GLS Dictionary
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
using Dictionary::exCantReadFile;
|
||||||
DEF_EX( exUserAbort, "User abort", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -264,14 +264,12 @@ bool MdictParser::parseCompressedBlock( qint64 compressedBlockSize,
|
||||||
|
|
||||||
case 0x02000000:
|
case 0x02000000:
|
||||||
// zlib compression
|
// zlib compression
|
||||||
decompressedBlock = zlibDecompress( buf, size );
|
decompressedBlock = zlibDecompress( buf, size, checksum );
|
||||||
|
if ( decompressedBlock.isEmpty() ) {
|
||||||
if ( !checkAdler32( decompressedBlock.constData(), decompressedBlock.size(), checksum ) ) {
|
gdWarning( "MDict: parseCompressedBlock: zlib: failed to decompress or checksum does not match" );
|
||||||
gdWarning( "MDict: parseCompressedBlock: zlib: checksum does not match" );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gdWarning( "MDict: parseCompressedBlock: unknown type" );
|
gdWarning( "MDict: parseCompressedBlock: unknown type" );
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -64,14 +64,11 @@ DEF_EX( exNotAnIfoFile, "Not an .ifo file", Dictionary::Ex )
|
||||||
DEF_EX_STR( exBadFieldInIfo, "Bad field in .ifo file encountered:", Dictionary::Ex )
|
DEF_EX_STR( exBadFieldInIfo, "Bad field in .ifo file encountered:", Dictionary::Ex )
|
||||||
DEF_EX_STR( exNoIdxFile, "No corresponding .idx file was found for", Dictionary::Ex )
|
DEF_EX_STR( exNoIdxFile, "No corresponding .idx file was found for", Dictionary::Ex )
|
||||||
DEF_EX_STR( exNoDictFile, "No corresponding .dict file was found for", Dictionary::Ex )
|
DEF_EX_STR( exNoDictFile, "No corresponding .dict file was found for", Dictionary::Ex )
|
||||||
DEF_EX_STR( exNoSynFile, "No corresponding .syn file was found for", Dictionary::Ex )
|
|
||||||
|
|
||||||
DEF_EX( ex64BitsNotSupported, "64-bit indices are not presently supported, sorry", Dictionary::Ex )
|
DEF_EX( ex64BitsNotSupported, "64-bit indices are not presently supported, sorry", Dictionary::Ex )
|
||||||
DEF_EX( exDicttypeNotSupported, "Dictionaries with dicttypes are not supported, sorry", Dictionary::Ex )
|
DEF_EX( exDicttypeNotSupported, "Dictionaries with dicttypes are not supported, sorry", Dictionary::Ex )
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
using Dictionary::exCantReadFile;
|
||||||
DEF_EX_STR( exWordIsTooLarge, "Enountered a word that is too large:", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exSuddenEndOfFile, "Sudden end of file", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionary::Ex )
|
DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionary::Ex )
|
||||||
|
|
|
@ -3,20 +3,21 @@
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
#include <lzma.h>
|
#include <lzma.h>
|
||||||
|
|
||||||
#define CHUNK_SIZE 2048
|
using std::string;
|
||||||
|
|
||||||
QByteArray zlibDecompress( const char * bufptr, unsigned length )
|
static constexpr qsizetype CHUNK_SIZE = 2048;
|
||||||
|
|
||||||
|
QByteArray zlibDecompress( const char * bufptr, unsigned length, uLong adler32_checksum )
|
||||||
{
|
{
|
||||||
z_stream zs;
|
z_stream zs{};
|
||||||
char buf[ CHUNK_SIZE ];
|
|
||||||
QByteArray str;
|
QByteArray str;
|
||||||
int res;
|
int res = Z_OK;
|
||||||
memset( &zs, 0, sizeof( zs ) );
|
|
||||||
zs.next_in = (Bytef *)bufptr;
|
zs.next_in = (Bytef *)bufptr;
|
||||||
zs.avail_in = length;
|
zs.avail_in = length;
|
||||||
res = inflateInit( &zs );
|
res = inflateInit( &zs );
|
||||||
|
|
||||||
if ( res == Z_OK ) {
|
if ( res == Z_OK ) {
|
||||||
|
char buf[ CHUNK_SIZE ];
|
||||||
while ( res != Z_STREAM_END ) {
|
while ( res != Z_STREAM_END ) {
|
||||||
zs.next_out = (Bytef *)buf;
|
zs.next_out = (Bytef *)buf;
|
||||||
zs.avail_out = CHUNK_SIZE;
|
zs.avail_out = CHUNK_SIZE;
|
||||||
|
@ -27,9 +28,7 @@ QByteArray zlibDecompress( const char * bufptr, unsigned length )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( inflateEnd( &zs ) != Z_OK || res != Z_STREAM_END || ( adler32_checksum != 0 && zs.adler != adler32_checksum ) ) {
|
||||||
inflateEnd( &zs );
|
|
||||||
if ( res != Z_STREAM_END ) {
|
|
||||||
str.clear();
|
str.clear();
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
@ -37,7 +36,7 @@ QByteArray zlibDecompress( const char * bufptr, unsigned length )
|
||||||
|
|
||||||
string decompressZlib( const char * bufptr, unsigned length )
|
string decompressZlib( const char * bufptr, unsigned length )
|
||||||
{
|
{
|
||||||
QByteArray b = zlibDecompress( bufptr, length );
|
QByteArray b = zlibDecompress( bufptr, length, 0 );
|
||||||
return string( b.constData(), b.size() );
|
return string( b.constData(), b.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::string;
|
/// @param adler32_checksum 0 to skip checksum
|
||||||
|
QByteArray zlibDecompress( const char * bufptr, unsigned length, unsigned long adler32_checksum );
|
||||||
|
|
||||||
QByteArray zlibDecompress( const char * bufptr, unsigned length );
|
std::string decompressZlib( const char * bufptr, unsigned length );
|
||||||
|
|
||||||
string decompressZlib( const char * bufptr, unsigned length );
|
std::string decompressBzip2( const char * bufptr, unsigned length );
|
||||||
|
|
||||||
string decompressBzip2( const char * bufptr, unsigned length );
|
std::string decompressLzma2( const char * bufptr, unsigned length, bool raw_decoder = false );
|
||||||
|
|
||||||
string decompressLzma2( const char * bufptr, unsigned length, bool raw_decoder = false );
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ class WebSiteDictionary: public Dictionary::Class
|
||||||
{
|
{
|
||||||
string name;
|
string name;
|
||||||
QByteArray urlTemplate;
|
QByteArray urlTemplate;
|
||||||
bool experimentalIframe;
|
|
||||||
QString iconFilename;
|
QString iconFilename;
|
||||||
bool inside_iframe;
|
bool inside_iframe;
|
||||||
QNetworkAccessManager & netMgr;
|
QNetworkAccessManager & netMgr;
|
||||||
|
@ -41,14 +40,8 @@ public:
|
||||||
name( name_ ),
|
name( name_ ),
|
||||||
iconFilename( iconFilename_ ),
|
iconFilename( iconFilename_ ),
|
||||||
inside_iframe( inside_iframe_ ),
|
inside_iframe( inside_iframe_ ),
|
||||||
netMgr( netMgr_ ),
|
netMgr( netMgr_ )
|
||||||
experimentalIframe( false )
|
|
||||||
{
|
{
|
||||||
if ( urlTemplate_.startsWith( "http://" ) || urlTemplate_.startsWith( "https://" ) ) {
|
|
||||||
experimentalIframe = true;
|
|
||||||
}
|
|
||||||
//else file:/// local dictionary file path
|
|
||||||
|
|
||||||
urlTemplate = QUrl( urlTemplate_ ).toEncoded();
|
urlTemplate = QUrl( urlTemplate_ ).toEncoded();
|
||||||
dictionaryDescription = urlTemplate_;
|
dictionaryDescription = urlTemplate_;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +53,9 @@ public:
|
||||||
|
|
||||||
map< Property, string > getProperties() noexcept override
|
map< Property, string > getProperties() noexcept override
|
||||||
{
|
{
|
||||||
return map< Property, string >();
|
map< Property, string > properties;
|
||||||
|
properties.insert( { Property::Url, urlTemplate.toStdString() } );
|
||||||
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long getArticleCount() noexcept override
|
unsigned long getArticleCount() noexcept override
|
||||||
|
@ -321,7 +316,7 @@ void WebSiteArticleRequest::requestFinished( QNetworkReply * r )
|
||||||
|
|
||||||
sptr< DataRequest > WebSiteDictionary::getArticle( wstring const & str,
|
sptr< DataRequest > WebSiteDictionary::getArticle( wstring const & str,
|
||||||
vector< wstring > const & /*alts*/,
|
vector< wstring > const & /*alts*/,
|
||||||
wstring const & context,
|
wstring const & /*context*/,
|
||||||
bool /*ignoreDiacritics*/ )
|
bool /*ignoreDiacritics*/ )
|
||||||
{
|
{
|
||||||
QString urlString = Utils::WebSite::urlReplaceWord( QString( urlTemplate ), QString::fromStdU32String( str ) );
|
QString urlString = Utils::WebSite::urlReplaceWord( QString( urlTemplate ), QString::fromStdU32String( str ) );
|
||||||
|
@ -335,24 +330,22 @@ sptr< DataRequest > WebSiteDictionary::getArticle( wstring const & str,
|
||||||
QUrl url( urlString );
|
QUrl url( urlString );
|
||||||
GlobalBroadcaster::instance()->addWhitelist( url.host() );
|
GlobalBroadcaster::instance()->addWhitelist( url.host() );
|
||||||
|
|
||||||
QString encodeUrl;
|
const QString & encodeUrl = urlString;
|
||||||
if ( experimentalIframe ) {
|
|
||||||
encodeUrl = "ifr://localhost?url=" + QUrl::toPercentEncoding( urlString );
|
if ( GlobalBroadcaster::instance()->getPreference()->openWebsiteInNewTab ) {
|
||||||
|
result += string( "<div><span>this website dictionary is opened in the new tab</span></div>" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
encodeUrl = urlString;
|
fmt::format_to( std::back_inserter( result ),
|
||||||
}
|
R"(<iframe id="gdexpandframe-{}" src="{}"
|
||||||
|
|
||||||
fmt::format_to( std::back_inserter( result ),
|
|
||||||
R"(<iframe id="gdexpandframe-{}" src="{}"
|
|
||||||
onmouseover="processIframeMouseOver('gdexpandframe-{}');"
|
onmouseover="processIframeMouseOver('gdexpandframe-{}');"
|
||||||
onmouseout="processIframeMouseOut();" scrolling="no"
|
onmouseout="processIframeMouseOut();" scrolling="no"
|
||||||
style="overflow:visible; width:100%; display:block; border:none;"
|
style="overflow:visible; width:100%; display:block; border:none;"
|
||||||
sandbox="allow-same-origin allow-scripts allow-popups"></iframe>)",
|
sandbox="allow-same-origin allow-scripts allow-popups"></iframe>)",
|
||||||
getId(),
|
getId(),
|
||||||
encodeUrl.toStdString(),
|
encodeUrl.toStdString(),
|
||||||
getId() );
|
getId() );
|
||||||
|
}
|
||||||
auto dr = std::make_shared< DataRequestInstant >( true );
|
auto dr = std::make_shared< DataRequestInstant >( true );
|
||||||
dr->appendString( result );
|
dr->appendString( result );
|
||||||
return dr;
|
return dr;
|
||||||
|
|
|
@ -81,7 +81,6 @@ namespace {
|
||||||
|
|
||||||
using Dictionary::exCantReadFile;
|
using Dictionary::exCantReadFile;
|
||||||
DEF_EX_STR( exNotXdxfFile, "The file is not an XDXF file:", Dictionary::Ex )
|
DEF_EX_STR( exNotXdxfFile, "The file is not an XDXF file:", Dictionary::Ex )
|
||||||
DEF_EX( exCorruptedIndex, "The index file is corrupted", Dictionary::Ex )
|
|
||||||
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
DEF_EX_STR( exDictzipError, "DICTZIP error", Dictionary::Ex )
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -85,6 +85,162 @@ QString ArticleView::scrollToFromDictionaryId( QString const & dictionaryId )
|
||||||
Q_ASSERT( !isScrollTo( dictionaryId ) );
|
Q_ASSERT( !isScrollTo( dictionaryId ) );
|
||||||
return scrollToPrefix + dictionaryId;
|
return scrollToPrefix + dictionaryId;
|
||||||
}
|
}
|
||||||
|
void ArticleView::setupWebview()
|
||||||
|
{ // setup GUI
|
||||||
|
this->webview = new ArticleWebView( this );
|
||||||
|
this->ftsSearchPanel = new FtsSearchPanel( this );
|
||||||
|
this->searchPanel = new SearchPanel( this );
|
||||||
|
this->searchPanel->hide();
|
||||||
|
this->ftsSearchPanel->hide();
|
||||||
|
|
||||||
|
auto * baseLayout = new QVBoxLayout( this );
|
||||||
|
|
||||||
|
this->tabWidget = new QTabWidget( this );
|
||||||
|
baseLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||||
|
baseLayout->addWidget( this->tabWidget );
|
||||||
|
|
||||||
|
auto * tab1 = new QWidget( tabWidget );
|
||||||
|
// Layout
|
||||||
|
auto * mainLayout = new QVBoxLayout( tab1 );
|
||||||
|
mainLayout->addWidget( this->webview );
|
||||||
|
mainLayout->addWidget( this->ftsSearchPanel );
|
||||||
|
mainLayout->addWidget( this->searchPanel );
|
||||||
|
|
||||||
|
this->webview->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||||
|
this->ftsSearchPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||||
|
this->searchPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||||
|
|
||||||
|
mainLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
this->tabWidget->addTab( tab1, "Dictionaries" );
|
||||||
|
this->tabWidget->setTabBarAutoHide( true );
|
||||||
|
|
||||||
|
// end UI setup
|
||||||
|
|
||||||
|
connect( this->searchPanel->previous, &QPushButton::clicked, this, &ArticleView::on_searchPrevious_clicked );
|
||||||
|
connect( this->searchPanel->next, &QPushButton::clicked, this, &ArticleView::on_searchNext_clicked );
|
||||||
|
connect( this->searchPanel->close, &QPushButton::clicked, this, &ArticleView::on_searchCloseButton_clicked );
|
||||||
|
connect( this->searchPanel->caseSensitive, &QCheckBox::toggled, this, &ArticleView::on_searchCaseSensitive_clicked );
|
||||||
|
connect( this->searchPanel->lineEdit, &QLineEdit::textEdited, this, &ArticleView::on_searchText_textEdited );
|
||||||
|
connect( this->searchPanel->lineEdit, &QLineEdit::returnPressed, this, &ArticleView::on_searchText_returnPressed );
|
||||||
|
connect( this->ftsSearchPanel->next, &QPushButton::clicked, this, &ArticleView::on_ftsSearchNext_clicked );
|
||||||
|
connect( this->ftsSearchPanel->previous, &QPushButton::clicked, this, &ArticleView::on_ftsSearchPrevious_clicked );
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
this->webview->setUp( const_cast< Config::Class * >( &this->cfg ) );
|
||||||
|
|
||||||
|
this->syncBackgroundColorWithCfgDarkReader();
|
||||||
|
|
||||||
|
this->goBackAction.setShortcut( QKeySequence( "Alt+Left" ) );
|
||||||
|
this->webview->addAction( &this->goBackAction );
|
||||||
|
connect( &this->goBackAction, &QAction::triggered, this, &ArticleView::back );
|
||||||
|
|
||||||
|
this->goForwardAction.setShortcut( QKeySequence( "Alt+Right" ) );
|
||||||
|
this->webview->addAction( &this->goForwardAction );
|
||||||
|
connect( &this->goForwardAction, &QAction::triggered, this, &ArticleView::forward );
|
||||||
|
|
||||||
|
this->webview->pageAction( QWebEnginePage::Copy )->setShortcut( QKeySequence::Copy );
|
||||||
|
this->webview->addAction( this->webview->pageAction( QWebEnginePage::Copy ) );
|
||||||
|
|
||||||
|
QAction * selectAll = this->webview->pageAction( QWebEnginePage::SelectAll );
|
||||||
|
selectAll->setShortcut( QKeySequence::SelectAll );
|
||||||
|
selectAll->setShortcutContext( Qt::WidgetWithChildrenShortcut );
|
||||||
|
this->webview->addAction( selectAll );
|
||||||
|
|
||||||
|
this->webview->setContextMenuPolicy( Qt::CustomContextMenu );
|
||||||
|
|
||||||
|
connect( this->webview, &QWebEngineView::loadFinished, this, &ArticleView::loadFinished );
|
||||||
|
|
||||||
|
connect( this->webview, &ArticleWebView::linkClicked, this, &ArticleView::linkClicked );
|
||||||
|
|
||||||
|
connect( this->webview->page(), &QWebEnginePage::titleChanged, this, &ArticleView::handleTitleChanged );
|
||||||
|
|
||||||
|
connect( this->webview, &QWidget::customContextMenuRequested, this, &ArticleView::contextMenuRequested );
|
||||||
|
|
||||||
|
connect( this->webview->page(), &QWebEnginePage::linkHovered, this, &ArticleView::linkHovered );
|
||||||
|
|
||||||
|
connect( this->webview, &ArticleWebView::doubleClicked, this, &ArticleView::doubleClicked );
|
||||||
|
|
||||||
|
this->pasteAction.setShortcut( QKeySequence::Paste );
|
||||||
|
this->webview->addAction( &this->pasteAction );
|
||||||
|
connect( &this->pasteAction, &QAction::triggered, this, &ArticleView::pasteTriggered );
|
||||||
|
|
||||||
|
this->articleUpAction.setShortcut( QKeySequence( "Alt+Up" ) );
|
||||||
|
this->webview->addAction( &this->articleUpAction );
|
||||||
|
connect( &this->articleUpAction, &QAction::triggered, this, &ArticleView::moveOneArticleUp );
|
||||||
|
|
||||||
|
this->articleDownAction.setShortcut( QKeySequence( "Alt+Down" ) );
|
||||||
|
this->webview->addAction( &this->articleDownAction );
|
||||||
|
connect( &this->articleDownAction, &QAction::triggered, this, &ArticleView::moveOneArticleDown );
|
||||||
|
|
||||||
|
this->selectCurrentArticleAction.setShortcut( QKeySequence( "Ctrl+Shift+A" ) );
|
||||||
|
this->selectCurrentArticleAction.setText( tr( "Select Current Article" ) );
|
||||||
|
this->webview->addAction( &this->selectCurrentArticleAction );
|
||||||
|
connect( &this->selectCurrentArticleAction, &QAction::triggered, this, &ArticleView::selectCurrentArticle );
|
||||||
|
|
||||||
|
this->copyAsTextAction.setShortcut( QKeySequence( "Ctrl+Shift+C" ) );
|
||||||
|
this->copyAsTextAction.setText( tr( "Copy as text" ) );
|
||||||
|
this->webview->addAction( &this->copyAsTextAction );
|
||||||
|
connect( &this->copyAsTextAction, &QAction::triggered, this, &ArticleView::copyAsText );
|
||||||
|
|
||||||
|
this->inspectAction.setShortcut( QKeySequence( Qt::Key_F12 ) );
|
||||||
|
this->inspectAction.setText( tr( "Inspect" ) );
|
||||||
|
this->webview->addAction( &this->inspectAction );
|
||||||
|
|
||||||
|
|
||||||
|
connect( &this->inspectAction, &QAction::triggered, this, &ArticleView::inspectElement );
|
||||||
|
|
||||||
|
this->webview->installEventFilter( this );
|
||||||
|
this->searchPanel->installEventFilter( this );
|
||||||
|
this->ftsSearchPanel->installEventFilter( this );
|
||||||
|
|
||||||
|
QWebEngineSettings * settings = this->webview->settings();
|
||||||
|
settings->setUnknownUrlSchemePolicy( QWebEngineSettings::UnknownUrlSchemePolicy::DisallowUnknownUrlSchemes );
|
||||||
|
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
||||||
|
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
|
||||||
|
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
|
||||||
|
settings->defaultSettings()->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
||||||
|
settings->defaultSettings()->setAttribute( QWebEngineSettings::LinksIncludedInFocusChain, false );
|
||||||
|
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 );
|
||||||
|
settings->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
||||||
|
settings->setAttribute( QWebEngineSettings::LinksIncludedInFocusChain, false );
|
||||||
|
settings->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
|
||||||
|
settings->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
|
||||||
|
settings->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
this->expandOptionalParts = this->cfg.preferences.alwaysExpandOptionalParts;
|
||||||
|
#ifndef Q_OS_MACOS
|
||||||
|
this->webview->grabGesture( Gestures::GDPinchGestureType );
|
||||||
|
this->webview->grabGesture( Gestures::GDSwipeGestureType );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArticleView::addWebsiteTab( QString name, QString url )
|
||||||
|
{
|
||||||
|
auto * view = new QWebEngineView( this );
|
||||||
|
view->load( url );
|
||||||
|
view->setZoomFactor( this->cfg.preferences.zoomFactor );
|
||||||
|
int index = tabWidget->count();
|
||||||
|
QString escaped = Utils::escapeAmps( name );
|
||||||
|
tabWidget->insertTab( index, view, escaped );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArticleView::clearWebsiteTabs()
|
||||||
|
{
|
||||||
|
int index = tabWidget->count();
|
||||||
|
// keep the first tab
|
||||||
|
while ( index-- > 1 ) {
|
||||||
|
tabWidget->removeTab( index );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ArticleView::ArticleView( QWidget * parent,
|
ArticleView::ArticleView( QWidget * parent,
|
||||||
ArticleNetworkAccessManager & nm,
|
ArticleNetworkAccessManager & nm,
|
||||||
|
@ -115,133 +271,11 @@ ArticleView::ArticleView( QWidget * parent,
|
||||||
translateLine( translateLine_ )
|
translateLine( translateLine_ )
|
||||||
{
|
{
|
||||||
// setup GUI
|
// setup GUI
|
||||||
webview = new ArticleWebView( this );
|
setupWebview();
|
||||||
ftsSearchPanel = new FtsSearchPanel( this );
|
|
||||||
searchPanel = new SearchPanel( this );
|
|
||||||
searchPanel->hide();
|
|
||||||
ftsSearchPanel->hide();
|
|
||||||
// Layout
|
|
||||||
auto * mainLayout = new QVBoxLayout( this );
|
|
||||||
mainLayout->addWidget( webview );
|
|
||||||
mainLayout->addWidget( ftsSearchPanel );
|
|
||||||
mainLayout->addWidget( searchPanel );
|
|
||||||
|
|
||||||
webview->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
auto html = this->articleNetMgr.getHtml( ResourceType::UNTITLE );
|
||||||
ftsSearchPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
|
|
||||||
searchPanel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
|
|
||||||
|
|
||||||
mainLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
||||||
|
|
||||||
// end UI setup
|
|
||||||
|
|
||||||
connect( searchPanel->previous, &QPushButton::clicked, this, &ArticleView::on_searchPrevious_clicked );
|
|
||||||
connect( searchPanel->next, &QPushButton::clicked, this, &ArticleView::on_searchNext_clicked );
|
|
||||||
connect( searchPanel->close, &QPushButton::clicked, this, &ArticleView::on_searchCloseButton_clicked );
|
|
||||||
connect( searchPanel->caseSensitive, &QCheckBox::toggled, this, &ArticleView::on_searchCaseSensitive_clicked );
|
|
||||||
connect( searchPanel->lineEdit, &QLineEdit::textEdited, this, &ArticleView::on_searchText_textEdited );
|
|
||||||
connect( searchPanel->lineEdit, &QLineEdit::returnPressed, this, &ArticleView::on_searchText_returnPressed );
|
|
||||||
connect( ftsSearchPanel->next, &QPushButton::clicked, this, &ArticleView::on_ftsSearchNext_clicked );
|
|
||||||
connect( ftsSearchPanel->previous, &QPushButton::clicked, this, &ArticleView::on_ftsSearchPrevious_clicked );
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
webview->setUp( const_cast< Config::Class * >( &cfg ) );
|
|
||||||
|
|
||||||
syncBackgroundColorWithCfgDarkReader();
|
|
||||||
|
|
||||||
goBackAction.setShortcut( QKeySequence( "Alt+Left" ) );
|
|
||||||
webview->addAction( &goBackAction );
|
|
||||||
connect( &goBackAction, &QAction::triggered, this, &ArticleView::back );
|
|
||||||
|
|
||||||
goForwardAction.setShortcut( QKeySequence( "Alt+Right" ) );
|
|
||||||
webview->addAction( &goForwardAction );
|
|
||||||
connect( &goForwardAction, &QAction::triggered, this, &ArticleView::forward );
|
|
||||||
|
|
||||||
webview->pageAction( QWebEnginePage::Copy )->setShortcut( QKeySequence::Copy );
|
|
||||||
webview->addAction( webview->pageAction( QWebEnginePage::Copy ) );
|
|
||||||
|
|
||||||
QAction * selectAll = webview->pageAction( QWebEnginePage::SelectAll );
|
|
||||||
selectAll->setShortcut( QKeySequence::SelectAll );
|
|
||||||
selectAll->setShortcutContext( Qt::WidgetWithChildrenShortcut );
|
|
||||||
webview->addAction( selectAll );
|
|
||||||
|
|
||||||
webview->setContextMenuPolicy( Qt::CustomContextMenu );
|
|
||||||
|
|
||||||
connect( webview, &QWebEngineView::loadFinished, this, &ArticleView::loadFinished );
|
|
||||||
|
|
||||||
connect( webview, &ArticleWebView::linkClicked, this, &ArticleView::linkClicked );
|
|
||||||
|
|
||||||
connect( webview->page(), &QWebEnginePage::titleChanged, this, &ArticleView::handleTitleChanged );
|
|
||||||
|
|
||||||
connect( webview, &QWidget::customContextMenuRequested, this, &ArticleView::contextMenuRequested );
|
|
||||||
|
|
||||||
connect( webview->page(), &QWebEnginePage::linkHovered, this, &ArticleView::linkHovered );
|
|
||||||
|
|
||||||
connect( webview, &ArticleWebView::doubleClicked, this, &ArticleView::doubleClicked );
|
|
||||||
|
|
||||||
pasteAction.setShortcut( QKeySequence::Paste );
|
|
||||||
webview->addAction( &pasteAction );
|
|
||||||
connect( &pasteAction, &QAction::triggered, this, &ArticleView::pasteTriggered );
|
|
||||||
|
|
||||||
articleUpAction.setShortcut( QKeySequence( "Alt+Up" ) );
|
|
||||||
webview->addAction( &articleUpAction );
|
|
||||||
connect( &articleUpAction, &QAction::triggered, this, &ArticleView::moveOneArticleUp );
|
|
||||||
|
|
||||||
articleDownAction.setShortcut( QKeySequence( "Alt+Down" ) );
|
|
||||||
webview->addAction( &articleDownAction );
|
|
||||||
connect( &articleDownAction, &QAction::triggered, this, &ArticleView::moveOneArticleDown );
|
|
||||||
|
|
||||||
selectCurrentArticleAction.setShortcut( QKeySequence( "Ctrl+Shift+A" ) );
|
|
||||||
selectCurrentArticleAction.setText( tr( "Select Current Article" ) );
|
|
||||||
webview->addAction( &selectCurrentArticleAction );
|
|
||||||
connect( &selectCurrentArticleAction, &QAction::triggered, this, &ArticleView::selectCurrentArticle );
|
|
||||||
|
|
||||||
copyAsTextAction.setShortcut( QKeySequence( "Ctrl+Shift+C" ) );
|
|
||||||
copyAsTextAction.setText( tr( "Copy as text" ) );
|
|
||||||
webview->addAction( ©AsTextAction );
|
|
||||||
connect( ©AsTextAction, &QAction::triggered, this, &ArticleView::copyAsText );
|
|
||||||
|
|
||||||
inspectAction.setShortcut( QKeySequence( Qt::Key_F12 ) );
|
|
||||||
inspectAction.setText( tr( "Inspect" ) );
|
|
||||||
webview->addAction( &inspectAction );
|
|
||||||
|
|
||||||
|
|
||||||
connect( &inspectAction, &QAction::triggered, this, &ArticleView::inspectElement );
|
|
||||||
|
|
||||||
webview->installEventFilter( this );
|
|
||||||
searchPanel->installEventFilter( this );
|
|
||||||
ftsSearchPanel->installEventFilter( this );
|
|
||||||
|
|
||||||
QWebEngineSettings * settings = webview->settings();
|
|
||||||
settings->setUnknownUrlSchemePolicy( QWebEngineSettings::UnknownUrlSchemePolicy::DisallowUnknownUrlSchemes );
|
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessRemoteUrls, true );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LocalContentCanAccessFileUrls, true );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
|
||||||
settings->defaultSettings()->setAttribute( QWebEngineSettings::LinksIncludedInFocusChain, false );
|
|
||||||
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 );
|
|
||||||
settings->setAttribute( QWebEngineSettings::ErrorPageEnabled, false );
|
|
||||||
settings->setAttribute( QWebEngineSettings::LinksIncludedInFocusChain, false );
|
|
||||||
settings->setAttribute( QWebEngineSettings::PlaybackRequiresUserGesture, false );
|
|
||||||
settings->setAttribute( QWebEngineSettings::JavascriptCanAccessClipboard, true );
|
|
||||||
settings->setAttribute( QWebEngineSettings::PrintElementBackgrounds, false );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto html = articleNetMgr.getHtml( ResourceType::UNTITLE );
|
|
||||||
|
|
||||||
webview->setHtml( QString::fromStdString( html ) );
|
|
||||||
|
|
||||||
expandOptionalParts = cfg.preferences.alwaysExpandOptionalParts;
|
|
||||||
#ifndef Q_OS_MACOS
|
|
||||||
webview->grabGesture( Gestures::GDPinchGestureType );
|
|
||||||
webview->grabGesture( Gestures::GDSwipeGestureType );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
this->webview->setHtml( QString::fromStdString( html ) );
|
||||||
connect( GlobalBroadcaster::instance(), &GlobalBroadcaster::dictionaryChanges, this, &ArticleView::setActiveDictIds );
|
connect( GlobalBroadcaster::instance(), &GlobalBroadcaster::dictionaryChanges, this, &ArticleView::setActiveDictIds );
|
||||||
connect( GlobalBroadcaster::instance(), &GlobalBroadcaster::dictionaryClear, this, &ArticleView::dictionaryClear );
|
connect( GlobalBroadcaster::instance(), &GlobalBroadcaster::dictionaryClear, this, &ArticleView::dictionaryClear );
|
||||||
|
|
||||||
|
@ -304,6 +338,7 @@ void ArticleView::showDefinition( QString const & word,
|
||||||
Contexts const & contexts_ )
|
Contexts const & contexts_ )
|
||||||
{
|
{
|
||||||
GlobalBroadcaster::instance()->pronounce_engine.reset();
|
GlobalBroadcaster::instance()->pronounce_engine.reset();
|
||||||
|
clearWebsiteTabs();
|
||||||
currentWord = word.trimmed();
|
currentWord = word.trimmed();
|
||||||
if ( currentWord.isEmpty() ) {
|
if ( currentWord.isEmpty() ) {
|
||||||
return;
|
return;
|
||||||
|
@ -351,7 +386,7 @@ void ArticleView::showDefinition( QString const & word,
|
||||||
|
|
||||||
QString mutedDicts = getMutedForGroup( group );
|
QString mutedDicts = getMutedForGroup( group );
|
||||||
|
|
||||||
if ( mutedDicts.size() ) {
|
if ( !mutedDicts.isEmpty() ) {
|
||||||
Utils::Url::addQueryItem( req, "muted", mutedDicts );
|
Utils::Url::addQueryItem( req, "muted", mutedDicts );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1235,6 +1270,17 @@ void ArticleView::syncBackgroundColorWithCfgDarkReader() const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArticleView::openWebsiteInNewTab( QString name, QString url )
|
||||||
|
{
|
||||||
|
QString escaped = Utils::escapeAmps( name );
|
||||||
|
|
||||||
|
//found existed QWebEngineView.
|
||||||
|
auto * view = new QWebEngineView( this );
|
||||||
|
view->load( QUrl( url ) );
|
||||||
|
|
||||||
|
tabWidget->addTab( view, escaped );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ArticleView::back()
|
void ArticleView::back()
|
||||||
{
|
{
|
||||||
|
@ -2162,6 +2208,11 @@ void ArticleView::clearContent()
|
||||||
|
|
||||||
webview->setHtml( QString::fromStdString( html ) );
|
webview->setHtml( QString::fromStdString( html ) );
|
||||||
}
|
}
|
||||||
|
void ArticleView::load( QString url )
|
||||||
|
{
|
||||||
|
webview->load( QUrl( url ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ResourceToSaveHandler::ResourceToSaveHandler( ArticleView * view, QString fileName ):
|
ResourceToSaveHandler::ResourceToSaveHandler( ArticleView * view, QString fileName ):
|
||||||
QObject( view ),
|
QObject( view ),
|
||||||
|
|
|
@ -96,7 +96,7 @@ public:
|
||||||
QAction * dictionaryBarToggled = nullptr,
|
QAction * dictionaryBarToggled = nullptr,
|
||||||
unsigned currentGroupId = 0 );
|
unsigned currentGroupId = 0 );
|
||||||
|
|
||||||
|
void openWebsiteInNewTab( QString name, QString url );
|
||||||
void setCurrentGroupId( unsigned currengGrgId );
|
void setCurrentGroupId( unsigned currengGrgId );
|
||||||
unsigned getCurrentGroupId();
|
unsigned getCurrentGroupId();
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ public:
|
||||||
|
|
||||||
~ArticleView();
|
~ArticleView();
|
||||||
|
|
||||||
|
void load( QString url );
|
||||||
/// Returns "gdfrom-" + dictionaryId.
|
/// Returns "gdfrom-" + dictionaryId.
|
||||||
static QString scrollToFromDictionaryId( QString const & dictionaryId );
|
static QString scrollToFromDictionaryId( QString const & dictionaryId );
|
||||||
|
|
||||||
|
@ -167,9 +167,14 @@ public:
|
||||||
/// \brief Set background as black if darkreader mode is enabled.
|
/// \brief Set background as black if darkreader mode is enabled.
|
||||||
void syncBackgroundColorWithCfgDarkReader() const;
|
void syncBackgroundColorWithCfgDarkReader() const;
|
||||||
|
|
||||||
|
void addWebsiteTab( QString name, QString url );
|
||||||
|
|
||||||
|
void clearWebsiteTabs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// widgets
|
// widgets
|
||||||
ArticleWebView * webview;
|
ArticleWebView * webview;
|
||||||
|
QTabWidget * tabWidget;
|
||||||
SearchPanel * searchPanel;
|
SearchPanel * searchPanel;
|
||||||
FtsSearchPanel * ftsSearchPanel;
|
FtsSearchPanel * ftsSearchPanel;
|
||||||
|
|
||||||
|
@ -411,6 +416,7 @@ private:
|
||||||
QString getMutedForGroup( unsigned group );
|
QString getMutedForGroup( unsigned group );
|
||||||
|
|
||||||
QStringList getMutedDictionaries( unsigned group );
|
QStringList getMutedDictionaries( unsigned group );
|
||||||
|
void setupWebview();
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResourceToSaveHandler: public QObject
|
class ResourceToSaveHandler: public QObject
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QWebEngineSettings>
|
#include <QWebEngineSettings>
|
||||||
#include <QProxyStyle>
|
#include <QProxyStyle>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
||||||
|
@ -401,15 +402,18 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
||||||
connect( wordsZoomOut, &QAction::triggered, this, &MainWindow::doWordsZoomOut );
|
connect( wordsZoomOut, &QAction::triggered, this, &MainWindow::doWordsZoomOut );
|
||||||
connect( wordsZoomBase, &QAction::triggered, this, &MainWindow::doWordsZoomBase );
|
connect( wordsZoomBase, &QAction::triggered, this, &MainWindow::doWordsZoomBase );
|
||||||
|
|
||||||
// tray icon
|
// tray icon
|
||||||
connect( trayIconMenu.addAction( tr( "Show &Main Window" ) ),
|
#ifndef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
&QAction::triggered,
|
connect( trayIconMenu.addAction( tr( "Show &Main Window" ) ), &QAction::triggered, this, [ this ] {
|
||||||
this,
|
this->toggleMainWindow( true );
|
||||||
&MainWindow::showMainWindow );
|
} );
|
||||||
|
#endif
|
||||||
trayIconMenu.addAction( enableScanningAction );
|
trayIconMenu.addAction( enableScanningAction );
|
||||||
|
|
||||||
|
#ifndef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
trayIconMenu.addSeparator();
|
trayIconMenu.addSeparator();
|
||||||
connect( trayIconMenu.addAction( tr( "&Quit" ) ), &QAction::triggered, this, &MainWindow::quitApp );
|
connect( trayIconMenu.addAction( tr( "&Quit" ) ), &QAction::triggered, this, &MainWindow::quitApp );
|
||||||
|
#endif
|
||||||
|
|
||||||
addGlobalAction( &escAction, [ this ]() {
|
addGlobalAction( &escAction, [ this ]() {
|
||||||
handleEsc();
|
handleEsc();
|
||||||
|
@ -716,6 +720,10 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
||||||
&GlobalBroadcaster::indexingDictionary,
|
&GlobalBroadcaster::indexingDictionary,
|
||||||
this,
|
this,
|
||||||
&MainWindow::showFTSIndexingName );
|
&MainWindow::showFTSIndexingName );
|
||||||
|
connect( GlobalBroadcaster::instance(),
|
||||||
|
&GlobalBroadcaster::websiteDictionarySignal,
|
||||||
|
this,
|
||||||
|
&MainWindow::openWebsiteInNewTab );
|
||||||
|
|
||||||
connect( &GlobalBroadcaster::instance()->pronounce_engine,
|
connect( &GlobalBroadcaster::instance()->pronounce_engine,
|
||||||
&PronounceEngine::emitAudio,
|
&PronounceEngine::emitAudio,
|
||||||
|
@ -1421,6 +1429,11 @@ void MainWindow::updateAppearances( QString const & addonStyle,
|
||||||
|
|
||||||
void MainWindow::trayIconUpdateOrInit()
|
void MainWindow::trayIconUpdateOrInit()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
trayIconMenu.setAsDockMenu();
|
||||||
|
ui.actionCloseToTray->setVisible( false );
|
||||||
|
#else
|
||||||
|
|
||||||
if ( !cfg.preferences.enableTrayIcon ) {
|
if ( !cfg.preferences.enableTrayIcon ) {
|
||||||
if ( trayIcon ) {
|
if ( trayIcon ) {
|
||||||
delete trayIcon;
|
delete trayIcon;
|
||||||
|
@ -1444,6 +1457,7 @@ void MainWindow::trayIconUpdateOrInit()
|
||||||
// The 'Close to tray' action is associated with the tray icon, so we hide
|
// The 'Close to tray' action is associated with the tray icon, so we hide
|
||||||
// or show it here.
|
// or show it here.
|
||||||
ui.actionCloseToTray->setVisible( cfg.preferences.enableTrayIcon );
|
ui.actionCloseToTray->setVisible( cfg.preferences.enableTrayIcon );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::wheelEvent( QWheelEvent * ev )
|
void MainWindow::wheelEvent( QWheelEvent * ev )
|
||||||
|
@ -2147,7 +2161,7 @@ void MainWindow::updateFoundInDictsList()
|
||||||
if ( dictionaries[ x ]->getId() == i->toUtf8().data() ) {
|
if ( dictionaries[ x ]->getId() == i->toUtf8().data() ) {
|
||||||
QString dictName = QString::fromUtf8( dictionaries[ x ]->getName().c_str() );
|
QString dictName = QString::fromUtf8( dictionaries[ x ]->getName().c_str() );
|
||||||
QString dictId = QString::fromUtf8( dictionaries[ x ]->getId().c_str() );
|
QString dictId = QString::fromUtf8( dictionaries[ x ]->getId().c_str() );
|
||||||
QListWidgetItem * item =
|
auto * item =
|
||||||
new QListWidgetItem( dictionaries[ x ]->getIcon(), dictName, ui.dictsList, QListWidgetItem::Type );
|
new QListWidgetItem( dictionaries[ x ]->getIcon(), dictName, ui.dictsList, QListWidgetItem::Type );
|
||||||
item->setData( Qt::UserRole, QVariant( dictId ) );
|
item->setData( Qt::UserRole, QVariant( dictId ) );
|
||||||
item->setToolTip( dictName );
|
item->setToolTip( dictName );
|
||||||
|
@ -2161,7 +2175,7 @@ void MainWindow::updateFoundInDictsList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if no item in dict List panel has been choose ,select first one.
|
//if no item in dict List panel has been choosen ,select first one.
|
||||||
if ( ui.dictsList->count() > 0 && ui.dictsList->selectedItems().empty() ) {
|
if ( ui.dictsList->count() > 0 && ui.dictsList->selectedItems().empty() ) {
|
||||||
ui.dictsList->setCurrentRow( 0 );
|
ui.dictsList->setCurrentRow( 0 );
|
||||||
}
|
}
|
||||||
|
@ -2172,7 +2186,7 @@ void MainWindow::updateBackForwardButtons()
|
||||||
{
|
{
|
||||||
ArticleView * view = getCurrentArticleView();
|
ArticleView * view = getCurrentArticleView();
|
||||||
|
|
||||||
if ( view ) {
|
if ( view != nullptr ) {
|
||||||
navBack->setEnabled( view->canGoBack() );
|
navBack->setEnabled( view->canGoBack() );
|
||||||
navForward->setEnabled( view->canGoForward() );
|
navForward->setEnabled( view->canGoForward() );
|
||||||
}
|
}
|
||||||
|
@ -2181,7 +2195,12 @@ void MainWindow::updateBackForwardButtons()
|
||||||
void MainWindow::updatePronounceAvailability()
|
void MainWindow::updatePronounceAvailability()
|
||||||
{
|
{
|
||||||
if ( ui.tabWidget->count() > 0 ) {
|
if ( ui.tabWidget->count() > 0 ) {
|
||||||
getCurrentArticleView()->hasSound( [ this ]( bool has ) {
|
ArticleView * pView = getCurrentArticleView();
|
||||||
|
if ( pView == nullptr ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pView->hasSound( [ this ]( bool has ) {
|
||||||
navPronounce->setEnabled( has );
|
navPronounce->setEnabled( has );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
@ -2532,7 +2551,7 @@ void MainWindow::handleEsc()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cfg.preferences.escKeyHidesMainWindow ) {
|
if ( cfg.preferences.escKeyHidesMainWindow ) {
|
||||||
toggleMainWindow();
|
toggleMainWindow( false );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
focusTranslateLine();
|
focusTranslateLine();
|
||||||
|
@ -2873,7 +2892,7 @@ void MainWindow::showTranslationForDicts( QString const & inWord,
|
||||||
ignoreDiacritics );
|
ignoreDiacritics );
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::toggleMainWindow( bool onlyShow )
|
void MainWindow::toggleMainWindow( bool ensureShow )
|
||||||
{
|
{
|
||||||
bool shown = false;
|
bool shown = false;
|
||||||
|
|
||||||
|
@ -2906,7 +2925,7 @@ void MainWindow::toggleMainWindow( bool onlyShow )
|
||||||
}
|
}
|
||||||
shown = true;
|
shown = true;
|
||||||
}
|
}
|
||||||
else if ( !onlyShow ) {
|
else if ( !ensureShow ) {
|
||||||
|
|
||||||
// On Windows and Linux, a hidden window won't show a task bar icon
|
// On Windows and Linux, a hidden window won't show a task bar icon
|
||||||
// When trayicon is enabled, the duplication is unneeded
|
// When trayicon is enabled, the duplication is unneeded
|
||||||
|
@ -2990,7 +3009,7 @@ void MainWindow::installHotKeys()
|
||||||
void MainWindow::hotKeyActivated( int hk )
|
void MainWindow::hotKeyActivated( int hk )
|
||||||
{
|
{
|
||||||
if ( !hk ) {
|
if ( !hk ) {
|
||||||
toggleMainWindow();
|
toggleMainWindow( false );
|
||||||
}
|
}
|
||||||
else if ( scanPopup ) {
|
else if ( scanPopup ) {
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
|
@ -3075,7 +3094,7 @@ void MainWindow::trayIconActivated( QSystemTrayIcon::ActivationReason r )
|
||||||
switch ( r ) {
|
switch ( r ) {
|
||||||
case QSystemTrayIcon::Trigger:
|
case QSystemTrayIcon::Trigger:
|
||||||
// Left click toggles the visibility of main window
|
// Left click toggles the visibility of main window
|
||||||
toggleMainWindow();
|
toggleMainWindow( false );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QSystemTrayIcon::MiddleClick:
|
case QSystemTrayIcon::MiddleClick:
|
||||||
|
@ -3088,10 +3107,6 @@ void MainWindow::trayIconActivated( QSystemTrayIcon::ActivationReason r )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showMainWindow()
|
|
||||||
{
|
|
||||||
toggleMainWindow( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::visitHomepage()
|
void MainWindow::visitHomepage()
|
||||||
{
|
{
|
||||||
|
@ -3718,7 +3733,8 @@ void MainWindow::messageFromAnotherInstanceReceived( QString const & message )
|
||||||
ArticleView * MainWindow::getCurrentArticleView()
|
ArticleView * MainWindow::getCurrentArticleView()
|
||||||
{
|
{
|
||||||
if ( QWidget * cw = ui.tabWidget->currentWidget() ) {
|
if ( QWidget * cw = ui.tabWidget->currentWidget() ) {
|
||||||
return dynamic_cast< ArticleView * >( cw );
|
auto * pView = dynamic_cast< ArticleView * >( cw );
|
||||||
|
return pView;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -3730,13 +3746,6 @@ void MainWindow::wordReceived( const QString & word )
|
||||||
respondToTranslationRequest( word, false );
|
respondToTranslationRequest( word, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::headwordReceived( const QString & word, const QString & ID )
|
|
||||||
{
|
|
||||||
toggleMainWindow( true );
|
|
||||||
setInputLineText( word, WildcardPolicy::EscapeWildcards, NoPopupChange );
|
|
||||||
respondToTranslationRequest( word, false, ArticleView::scrollToFromDictionaryId( ID ), false );
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::updateFavoritesMenu()
|
void MainWindow::updateFavoritesMenu()
|
||||||
{
|
{
|
||||||
if ( ui.favoritesPane->isVisible() ) {
|
if ( ui.favoritesPane->isVisible() ) {
|
||||||
|
@ -4141,7 +4150,13 @@ void MainWindow::showDictionaryHeadwords( Dictionary::Class * dict )
|
||||||
headwordsDlg = new DictHeadwords( this, cfg, dict );
|
headwordsDlg = new DictHeadwords( this, cfg, dict );
|
||||||
addGlobalActionsToDialog( headwordsDlg );
|
addGlobalActionsToDialog( headwordsDlg );
|
||||||
addGroupComboBoxActionsToDialog( headwordsDlg, groupList );
|
addGroupComboBoxActionsToDialog( headwordsDlg, groupList );
|
||||||
connect( headwordsDlg, &DictHeadwords::headwordSelected, this, &MainWindow::headwordReceived );
|
connect( headwordsDlg,
|
||||||
|
&DictHeadwords::headwordSelected,
|
||||||
|
this,
|
||||||
|
[ this ]( QString const & headword, QString const & dictID ) {
|
||||||
|
setInputLineText( headword, WildcardPolicy::EscapeWildcards, NoPopupChange );
|
||||||
|
respondToTranslationRequest( headword, false, ArticleView::scrollToFromDictionaryId( dictID ), false );
|
||||||
|
} );
|
||||||
connect( headwordsDlg,
|
connect( headwordsDlg,
|
||||||
&DictHeadwords::closeDialog,
|
&DictHeadwords::closeDialog,
|
||||||
this,
|
this,
|
||||||
|
@ -4374,6 +4389,19 @@ void MainWindow::showFTSIndexingName( QString const & name )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::openWebsiteInNewTab( QString name, QString url )
|
||||||
|
{
|
||||||
|
// QString escaped = Utils::escapeAmps( name );
|
||||||
|
|
||||||
|
// auto * view = new ArticleView( this, articleNetMgr, audioPlayerFactory.player(), cfg );
|
||||||
|
// view->load( url );
|
||||||
|
// int index = cfg.preferences.newTabsOpenAfterCurrentOne ? ui.tabWidget->currentIndex() + 1 : ui.tabWidget->count();
|
||||||
|
|
||||||
|
// ui.tabWidget->insertTab( index, view, escaped );
|
||||||
|
// mruList.append( dynamic_cast< QWidget * >( view ) );
|
||||||
|
getCurrentArticleView()->addWebsiteTab( std::move( name ), url );
|
||||||
|
}
|
||||||
|
|
||||||
QString MainWindow::unescapeTabHeader( QString const & header )
|
QString MainWindow::unescapeTabHeader( QString const & header )
|
||||||
{
|
{
|
||||||
// Reset table header to original headword
|
// Reset table header to original headword
|
||||||
|
|
|
@ -67,7 +67,6 @@ public slots:
|
||||||
void messageFromAnotherInstanceReceived( QString const & );
|
void messageFromAnotherInstanceReceived( QString const & );
|
||||||
void showStatusBarMessage( QString const &, int, QPixmap const & );
|
void showStatusBarMessage( QString const &, int, QPixmap const & );
|
||||||
void wordReceived( QString const & );
|
void wordReceived( QString const & );
|
||||||
void headwordReceived( QString const &, QString const & );
|
|
||||||
void headwordFromFavorites( QString const &, QString const & );
|
void headwordFromFavorites( QString const &, QString const & );
|
||||||
void quitApp();
|
void quitApp();
|
||||||
|
|
||||||
|
@ -226,9 +225,8 @@ private:
|
||||||
/// group, or to all dictionaries if there are no groups.
|
/// group, or to all dictionaries if there are no groups.
|
||||||
vector< sptr< Dictionary::Class > > const & getActiveDicts();
|
vector< sptr< Dictionary::Class > > const & getActiveDicts();
|
||||||
|
|
||||||
/// Brings the main window to front if it's not currently, or hides it
|
/// @param ensureShow only ensure the window will be shown and no "toggling"
|
||||||
/// otherwise. The hiding part is omitted if onlyShow is true.
|
void toggleMainWindow( bool ensureShow );
|
||||||
void toggleMainWindow( bool onlyShow = false );
|
|
||||||
|
|
||||||
/// Creates hotkeyWrapper and hooks the currently set keys for it
|
/// Creates hotkeyWrapper and hooks the currently set keys for it
|
||||||
void installHotKeys();
|
void installHotKeys();
|
||||||
|
@ -292,6 +290,7 @@ private slots:
|
||||||
void openDictionaryFolder( QString const & id );
|
void openDictionaryFolder( QString const & id );
|
||||||
|
|
||||||
void showFTSIndexingName( QString const & name );
|
void showFTSIndexingName( QString const & name );
|
||||||
|
void openWebsiteInNewTab( QString name, QString url );
|
||||||
|
|
||||||
void handleAddToFavoritesButton();
|
void handleAddToFavoritesButton();
|
||||||
|
|
||||||
|
@ -398,8 +397,6 @@ private slots:
|
||||||
|
|
||||||
void setAutostart( bool );
|
void setAutostart( bool );
|
||||||
|
|
||||||
void showMainWindow();
|
|
||||||
|
|
||||||
void visitHomepage();
|
void visitHomepage();
|
||||||
void visitForum();
|
void visitForum();
|
||||||
void openConfigFolder();
|
void openConfigFolder();
|
||||||
|
|
|
@ -174,6 +174,11 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
||||||
ui.hideSingleTab->setChecked( p.hideSingleTab );
|
ui.hideSingleTab->setChecked( p.hideSingleTab );
|
||||||
ui.mruTabOrder->setChecked( p.mruTabOrder );
|
ui.mruTabOrder->setChecked( p.mruTabOrder );
|
||||||
ui.enableTrayIcon->setChecked( p.enableTrayIcon );
|
ui.enableTrayIcon->setChecked( p.enableTrayIcon );
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS // macOS uses the dock menu instead of the tray icon
|
||||||
|
ui.enableTrayIcon->hide();
|
||||||
|
#endif
|
||||||
|
|
||||||
ui.startToTray->setChecked( p.startToTray );
|
ui.startToTray->setChecked( p.startToTray );
|
||||||
ui.closeToTray->setChecked( p.closeToTray );
|
ui.closeToTray->setChecked( p.closeToTray );
|
||||||
ui.cbAutostart->setChecked( p.autoStart );
|
ui.cbAutostart->setChecked( p.autoStart );
|
||||||
|
@ -361,6 +366,7 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
||||||
|
|
||||||
//Misc
|
//Misc
|
||||||
ui.removeInvalidIndexOnExit->setChecked( p.removeInvalidIndexOnExit );
|
ui.removeInvalidIndexOnExit->setChecked( p.removeInvalidIndexOnExit );
|
||||||
|
ui.openWebsiteInNewTab->setChecked( p.openWebsiteInNewTab );
|
||||||
|
|
||||||
// Add-on styles
|
// Add-on styles
|
||||||
ui.addonStylesLabel->setVisible( ui.addonStyles->count() > 1 );
|
ui.addonStylesLabel->setVisible( ui.addonStyles->count() > 1 );
|
||||||
|
@ -520,6 +526,7 @@ Config::Preferences Preferences::getPreferences()
|
||||||
p.clearNetworkCacheOnExit = ui.clearNetworkCacheOnExit->isChecked();
|
p.clearNetworkCacheOnExit = ui.clearNetworkCacheOnExit->isChecked();
|
||||||
|
|
||||||
p.removeInvalidIndexOnExit = ui.removeInvalidIndexOnExit->isChecked();
|
p.removeInvalidIndexOnExit = ui.removeInvalidIndexOnExit->isChecked();
|
||||||
|
p.openWebsiteInNewTab = ui.openWebsiteInNewTab->isChecked();
|
||||||
|
|
||||||
p.addonStyle = ui.addonStyles->getCurrentStyle();
|
p.addonStyle = ui.addonStyles->getCurrentStyle();
|
||||||
|
|
||||||
|
|
|
@ -1938,6 +1938,13 @@ from Stardict, Babylon and GLS dictionaries</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="openWebsiteInNewTab">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open website dictionary in seperate tab</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
Loading…
Reference in a new issue