mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 23:34:06 +00:00
Merge branch 'staged' into dev
This commit is contained in:
commit
9ef50e807d
|
@ -1157,13 +1157,9 @@ void BtreeIndex::findArticleLinks( QVector< WordArticleLink > * articleLinks,
|
|||
}
|
||||
}
|
||||
|
||||
void BtreeIndex::findHeadWords( QSet< uint32_t > offsets, int & index, QSet< QString > * headwords, uint32_t length )
|
||||
void BtreeIndex::findHeadWords( QList< uint32_t > offsets, int & index, QSet< QString > * headwords, uint32_t length )
|
||||
{
|
||||
int i = 0;
|
||||
for ( auto begin = offsets.begin(); begin != offsets.end(); begin++, i++ ) {
|
||||
if ( i < index ) {
|
||||
continue;
|
||||
}
|
||||
for ( auto begin = offsets.begin() + index; begin != offsets.end(); begin++ ) {
|
||||
findSingleNodeHeadwords( *begin, headwords );
|
||||
index++;
|
||||
|
||||
|
@ -1207,8 +1203,8 @@ void BtreeIndex::findSingleNodeHeadwords( uint32_t offsets, QSet< QString > * he
|
|||
}
|
||||
}
|
||||
|
||||
//find the next chain ptr ,which is large than this currentChainPtr
|
||||
QSet< uint32_t > BtreeIndex::findNodes()
|
||||
//find the next chain ptr ,which is larger than this currentChainPtr
|
||||
QList< uint32_t > BtreeIndex::findNodes()
|
||||
{
|
||||
QMutexLocker _( idxFileMutex );
|
||||
|
||||
|
@ -1219,12 +1215,12 @@ QSet< uint32_t > BtreeIndex::findNodes()
|
|||
}
|
||||
|
||||
char const * leaf = &rootNode.front();
|
||||
QSet< uint32_t > leafOffset;
|
||||
QList< uint32_t > leafOffset;
|
||||
|
||||
uint32_t leafEntries;
|
||||
leafEntries = *(uint32_t *)leaf;
|
||||
if ( leafEntries != 0xffffFFFF ) {
|
||||
leafOffset.insert( rootOffset );
|
||||
leafOffset.append( rootOffset );
|
||||
return leafOffset;
|
||||
}
|
||||
|
||||
|
@ -1234,8 +1230,9 @@ QSet< uint32_t > BtreeIndex::findNodes()
|
|||
uint32_t * offsets = (uint32_t *)leaf + 1;
|
||||
uint32_t i = 0;
|
||||
|
||||
while ( i++ < ( indexNodeSize + 1 ) )
|
||||
leafOffset.insert( *( offsets++ ) );
|
||||
while ( i++ < ( indexNodeSize + 1 ) ) {
|
||||
leafOffset.append( *( offsets++ ) );
|
||||
}
|
||||
|
||||
return leafOffset;
|
||||
}
|
||||
|
|
|
@ -100,9 +100,9 @@ public:
|
|||
QSet< QString > * headwords,
|
||||
QAtomicInt * isCancelled = 0 );
|
||||
|
||||
void findHeadWords( QSet< uint32_t > offsets, int & index, QSet< QString > * headwords, uint32_t length );
|
||||
void findHeadWords( QList< uint32_t > offsets, int & index, QSet< QString > * headwords, uint32_t length );
|
||||
void findSingleNodeHeadwords( uint32_t offsets, QSet< QString > * headwords );
|
||||
QSet< uint32_t > findNodes();
|
||||
QList< uint32_t > findNodes();
|
||||
|
||||
/// Retrieve headwords for presented article addresses
|
||||
void
|
||||
|
@ -197,15 +197,6 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Sort articles offsets for full-text search in dictionary-specific order
|
||||
// to increase of articles retrieving speed
|
||||
// Default - simple sorting in increase order
|
||||
virtual void sortArticlesOffsetsForFTS( QVector< uint32_t > & offsets, QAtomicInt & isCancelled )
|
||||
{
|
||||
Q_UNUSED( isCancelled );
|
||||
std::sort( offsets.begin(), offsets.end() );
|
||||
}
|
||||
|
||||
/// Called before each matching operation to ensure that any child init
|
||||
/// has completed. Mainly used for deferred init. The default implementation
|
||||
/// does nothing.
|
||||
|
|
|
@ -636,7 +636,6 @@ public:
|
|||
|
||||
quint64 getArticlePos( uint32_t articleNumber );
|
||||
|
||||
void sortArticlesOffsetsForFTS( QVector< uint32_t > & offsets, QAtomicInt & isCancelled ) override;
|
||||
void makeFTSIndex( QAtomicInt & isCancelled, bool firstIteration ) override;
|
||||
|
||||
void setFTSParameters( Config::FullTextSearch const & fts ) override
|
||||
|
@ -888,11 +887,6 @@ quint64 SlobDictionary::getArticlePos( uint32_t articleNumber )
|
|||
return ( ( (quint64)( entry.binIndex ) ) << 32 ) | entry.itemIndex;
|
||||
}
|
||||
|
||||
void SlobDictionary::sortArticlesOffsetsForFTS( QVector< uint32_t > & offsets, QAtomicInt & isCancelled )
|
||||
{
|
||||
//Currently , we use xapian to create the fulltext index. The order of offsets is no important.
|
||||
}
|
||||
|
||||
void SlobDictionary::makeFTSIndex( QAtomicInt & isCancelled, bool firstIteration )
|
||||
{
|
||||
if ( !( Dictionary::needToRebuildIndex( getDictionaryFilenames(), ftsIdxName )
|
||||
|
|
|
@ -225,8 +225,6 @@ public:
|
|||
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
|
||||
}
|
||||
|
||||
void sortArticlesOffsetsForFTS( QVector< uint32_t > & offsets, QAtomicInt & isCancelled ) override;
|
||||
|
||||
protected:
|
||||
|
||||
void loadIcon() noexcept override;
|
||||
|
@ -504,25 +502,6 @@ void ZimDictionary::makeFTSIndex( QAtomicInt & isCancelled, bool firstIteration
|
|||
}
|
||||
}
|
||||
|
||||
void ZimDictionary::sortArticlesOffsetsForFTS( QVector< uint32_t > & offsets, QAtomicInt & isCancelled )
|
||||
{
|
||||
QVector< QPair< quint32, uint32_t > > offsetsWithClusters;
|
||||
offsetsWithClusters.reserve( offsets.size() );
|
||||
|
||||
for ( QVector< uint32_t >::ConstIterator it = offsets.constBegin(); it != offsets.constEnd(); ++it ) {
|
||||
if ( Utils::AtomicInt::loadAcquire( isCancelled ) )
|
||||
return;
|
||||
|
||||
QMutexLocker _( &zimMutex );
|
||||
offsetsWithClusters.append( QPair< uint32_t, quint32 >( getArticleCluster( df, *it ), *it ) );
|
||||
}
|
||||
|
||||
std::sort( offsetsWithClusters.begin(), offsetsWithClusters.end() );
|
||||
|
||||
for ( int i = 0; i < offsetsWithClusters.size(); i++ )
|
||||
offsets[ i ] = offsetsWithClusters.at( i ).second;
|
||||
}
|
||||
|
||||
void ZimDictionary::getArticleText( uint32_t articleAddress, QString & headword, QString & text )
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -91,8 +91,6 @@ void makeFTSIndex( BtreeIndexing::BtreeDictionary * dict, QAtomicInt & isCancell
|
|||
if ( Utils::AtomicInt::loadAcquire( isCancelled ) )
|
||||
throw exUserAbort();
|
||||
|
||||
// dict->sortArticlesOffsetsForFTS( offsets, isCancelled );
|
||||
|
||||
// incremental build the index.
|
||||
// get the last address.
|
||||
bool skip = true;
|
||||
|
|
|
@ -453,26 +453,8 @@ void FullTextSearchDialog::itemClicked( const QModelIndex & idx )
|
|||
auto searchText = ui.searchLine->text();
|
||||
searchText.replace( RX::Ftx::tokenBoundary, " " );
|
||||
|
||||
auto it = RX::Ftx::token.globalMatch( searchText );
|
||||
QString firstAvailbeItem;
|
||||
while ( it.hasNext() ) {
|
||||
QRegularExpressionMatch match = it.next();
|
||||
|
||||
auto p = match.captured();
|
||||
if ( p.startsWith( '-' ) )
|
||||
continue;
|
||||
|
||||
//the searched text should be like "term".remove enclosed double quotation marks.
|
||||
if ( p.startsWith( "\"" ) ) {
|
||||
p.remove( "\"" );
|
||||
}
|
||||
|
||||
firstAvailbeItem = p;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !firstAvailbeItem.isEmpty() ) {
|
||||
reg = QRegularExpression( firstAvailbeItem, QRegularExpression::CaseInsensitiveOption );
|
||||
if ( !searchText.isEmpty() ) {
|
||||
reg = QRegularExpression( searchText, QRegularExpression::CaseInsensitiveOption );
|
||||
}
|
||||
|
||||
emit showTranslationFor( headword, results[ idx.row() ].dictIDs, reg, false );
|
||||
|
|
|
@ -5,6 +5,7 @@ HeadwordListModel::HeadwordListModel( QObject * parent ):
|
|||
QAbstractListModel( parent ),
|
||||
filtering( false ),
|
||||
totalSize( 0 ),
|
||||
finished( false ),
|
||||
index( 0 ),
|
||||
ptr( nullptr )
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ int HeadwordListModel::totalCount() const
|
|||
|
||||
bool HeadwordListModel::isFinish() const
|
||||
{
|
||||
return words.size() >= totalSize;
|
||||
return finished || ( words.size() >= totalSize );
|
||||
}
|
||||
|
||||
// export headword
|
||||
|
@ -35,15 +36,38 @@ QString HeadwordListModel::getRow( int row )
|
|||
return fileSortedList.at( row );
|
||||
}
|
||||
|
||||
void HeadwordListModel::setFilter( QRegularExpression reg )
|
||||
void HeadwordListModel::setFilter( const QRegularExpression & reg )
|
||||
{
|
||||
if ( reg.pattern().isEmpty() ) {
|
||||
filtering = false;
|
||||
//if the headword is already finished loaded, do nothing。
|
||||
if ( finished ) {
|
||||
return;
|
||||
}
|
||||
filtering = true;
|
||||
//back to normal state ,restore the original model;
|
||||
if ( reg.pattern().isEmpty() ) {
|
||||
QMutexLocker _( &lock );
|
||||
//race condition.
|
||||
if ( !filtering ) {
|
||||
return;
|
||||
}
|
||||
filtering = false;
|
||||
|
||||
//reset to previous models
|
||||
beginResetModel();
|
||||
words = QStringList( original_words );
|
||||
endResetModel();
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
QMutexLocker _( &lock );
|
||||
//the first time to enter filtering mode.
|
||||
if ( !filtering ) {
|
||||
filtering = true;
|
||||
original_words = QStringList( words );
|
||||
}
|
||||
}
|
||||
filterWords.clear();
|
||||
auto sr = _dict->prefixMatch( gd::removeTrailingZero( reg.pattern() ), 500 );
|
||||
auto sr = _dict->prefixMatch( gd::removeTrailingZero( reg.pattern() ), maxFilterResults );
|
||||
connect( sr.get(), &Dictionary::Request::finished, this, &HeadwordListModel::requestFinished, Qt::QueuedConnection );
|
||||
queuedRequests.push_back( sr );
|
||||
}
|
||||
|
@ -54,25 +78,6 @@ void HeadwordListModel::appendWord( const QString & word )
|
|||
words.append( word );
|
||||
}
|
||||
|
||||
void HeadwordListModel::addMatches( QStringList matches )
|
||||
{
|
||||
QStringList filtered;
|
||||
for ( auto const & w : matches ) {
|
||||
if ( !containWord( w ) ) {
|
||||
filtered << w;
|
||||
}
|
||||
}
|
||||
|
||||
if ( filtered.isEmpty() )
|
||||
return;
|
||||
|
||||
beginInsertRows( QModelIndex(), words.size(), words.size() + filtered.count() - 1 );
|
||||
for ( const auto & word : filtered ) {
|
||||
appendWord( word );
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void HeadwordListModel::requestFinished()
|
||||
{
|
||||
// See how many new requests have finished, and if we have any new results
|
||||
|
@ -81,8 +86,7 @@ void HeadwordListModel::requestFinished()
|
|||
if ( !( *i )->getErrorString().isEmpty() ) {
|
||||
qDebug() << "error:" << ( *i )->getErrorString();
|
||||
}
|
||||
|
||||
if ( ( *i )->matchesCount() ) {
|
||||
else if ( ( *i )->matchesCount() ) {
|
||||
auto allmatches = ( *i )->getAllMatches();
|
||||
for ( auto & match : allmatches )
|
||||
filterWords.append( QString::fromStdU32String( match.word ) );
|
||||
|
@ -94,19 +98,13 @@ void HeadwordListModel::requestFinished()
|
|||
}
|
||||
|
||||
if ( queuedRequests.empty() ) {
|
||||
QStringList filtered;
|
||||
for ( auto & w : filterWords ) {
|
||||
if ( !containWord( w ) ) {
|
||||
filtered << w;
|
||||
}
|
||||
}
|
||||
if ( filtered.isEmpty() )
|
||||
if ( filterWords.isEmpty() ) {
|
||||
return;
|
||||
|
||||
beginInsertRows( QModelIndex(), words.size(), words.size() + filtered.count() - 1 );
|
||||
for ( const auto & word : filtered )
|
||||
appendWord( word );
|
||||
endInsertRows();
|
||||
}
|
||||
beginResetModel();
|
||||
words = QStringList( filterWords );
|
||||
endResetModel();
|
||||
emit numberPopulated( words.size() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,16 +129,29 @@ QVariant HeadwordListModel::data( const QModelIndex & index, int role ) const
|
|||
|
||||
bool HeadwordListModel::canFetchMore( const QModelIndex & parent ) const
|
||||
{
|
||||
if ( parent.isValid() || filtering )
|
||||
if ( parent.isValid() || filtering || finished )
|
||||
return false;
|
||||
return ( words.size() < totalSize );
|
||||
}
|
||||
|
||||
void HeadwordListModel::fetchMore( const QModelIndex & parent )
|
||||
{
|
||||
if ( parent.isValid() || filtering )
|
||||
if ( parent.isValid() || filtering || finished )
|
||||
return;
|
||||
|
||||
//arbitrary number
|
||||
if ( totalSize < HEADWORDS_MAX_LIMIT ) {
|
||||
finished = true;
|
||||
|
||||
beginInsertRows( QModelIndex(), 0, totalSize - 1 );
|
||||
_dict->getHeadwords( words );
|
||||
|
||||
endInsertRows();
|
||||
emit numberPopulated( words.size() );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QSet< QString > headword;
|
||||
QMutexLocker _( &lock );
|
||||
|
||||
|
@ -149,15 +160,9 @@ void HeadwordListModel::fetchMore( const QModelIndex & parent )
|
|||
return;
|
||||
}
|
||||
|
||||
QSet< QString > filtered;
|
||||
beginInsertRows( QModelIndex(), words.size(), words.size() + headword.count() - 1 );
|
||||
for ( const auto & word : std::as_const( headword ) ) {
|
||||
if ( !containWord( word ) )
|
||||
filtered.insert( word );
|
||||
}
|
||||
|
||||
beginInsertRows( QModelIndex(), words.size(), words.size() + filtered.count() - 1 );
|
||||
for ( const auto & word : filtered ) {
|
||||
appendWord( word );
|
||||
words << word;
|
||||
}
|
||||
endInsertRows();
|
||||
|
||||
|
@ -174,6 +179,11 @@ bool HeadwordListModel::containWord( const QString & word )
|
|||
return hashedWords.contains( word );
|
||||
}
|
||||
|
||||
void HeadwordListModel::setMaxFilterResults( int _maxFilterResults )
|
||||
{
|
||||
this->maxFilterResults = _maxFilterResults;
|
||||
}
|
||||
|
||||
QSet< QString > HeadwordListModel::getRemainRows( int & nodeIndex )
|
||||
{
|
||||
QSet< QString > headword;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <QAbstractListModel>
|
||||
#include <QStringList>
|
||||
|
||||
static const int HEADWORDS_MAX_LIMIT = 500000;
|
||||
class HeadwordListModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -19,15 +20,14 @@ public:
|
|||
bool isFinish() const;
|
||||
QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const override;
|
||||
QString getRow( int row );
|
||||
void setFilter( QRegularExpression );
|
||||
void setFilter( const QRegularExpression & );
|
||||
void appendWord( const QString & word );
|
||||
void addMatches( QStringList matches );
|
||||
int getCurrentIndex() const;
|
||||
bool containWord( const QString & word );
|
||||
QSet< QString > getRemainRows( int & nodeIndex );
|
||||
void setMaxFilterResults( int _maxFilterResults );
|
||||
signals:
|
||||
void numberPopulated( int number );
|
||||
void finished( int number );
|
||||
|
||||
public slots:
|
||||
void setDict( Dictionary::Class * dict );
|
||||
|
@ -39,11 +39,14 @@ protected:
|
|||
|
||||
private:
|
||||
QStringList words;
|
||||
QStringList original_words;
|
||||
QSet< QString > hashedWords;
|
||||
QStringList filterWords;
|
||||
bool filtering;
|
||||
QStringList fileSortedList;
|
||||
long totalSize;
|
||||
int maxFilterResults;
|
||||
bool finished;
|
||||
Dictionary::Class * _dict;
|
||||
int index;
|
||||
char * ptr;
|
||||
|
|
|
@ -2,57 +2,14 @@
|
|||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "keyboardstate.hh"
|
||||
#include <QObject> // To get Qt Q_OS defines
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#elif defined( HAVE_X11 )
|
||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QX11Info>
|
||||
#endif
|
||||
#include <X11/X.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#elif defined Q_OS_MAC
|
||||
#define __SECURITYHI__
|
||||
#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
#include <QApplication>
|
||||
|
||||
bool KeyboardState::checkModifiersPressed( int mask )
|
||||
{
|
||||
#if defined( Q_OS_WIN32 )
|
||||
auto modifiers = QApplication::queryKeyboardModifiers();
|
||||
|
||||
return !( ( mask & Alt && !( GetAsyncKeyState( VK_MENU ) & 0x8000 ) )
|
||||
|| ( mask & Ctrl && !( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) )
|
||||
|| ( mask & Shift && !( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) )
|
||||
|| ( mask & LeftAlt && !( GetAsyncKeyState( VK_LMENU ) & 0x8000 ) )
|
||||
|| ( mask & RightAlt && !( GetAsyncKeyState( VK_RMENU ) & 0x8000 ) )
|
||||
|| ( mask & LeftCtrl && !( GetAsyncKeyState( VK_LCONTROL ) & 0x8000 ) )
|
||||
|| ( mask & RightCtrl && !( GetAsyncKeyState( VK_RCONTROL ) & 0x8000 ) )
|
||||
|| ( mask & LeftShift && !( GetAsyncKeyState( VK_LSHIFT ) & 0x8000 ) )
|
||||
|| ( mask & RightShift && !( GetAsyncKeyState( VK_RSHIFT ) & 0x8000 ) ) );
|
||||
|
||||
#elif defined Q_OS_MAC
|
||||
UInt32 keys = GetCurrentKeyModifiers();
|
||||
return !( ( mask & Alt && !( keys & ( 1 << optionKeyBit ) ) ) || ( mask & Ctrl && !( keys & ( 1 << cmdKeyBit ) ) )
|
||||
|| ( 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( displayID, XkbUseCoreKbd, &state );
|
||||
|
||||
return !( ( mask & Alt && !( state.base_mods & Mod1Mask ) ) || ( mask & Ctrl && !( state.base_mods & ControlMask ) )
|
||||
|| ( mask & Shift && !( state.base_mods & ShiftMask ) )
|
||||
|| ( mask & Win && !( state.base_mods & Mod4Mask ) ) );
|
||||
#endif
|
||||
return !( ( mask & Alt && !( modifiers.testFlag( Qt::AltModifier ) ) )
|
||||
|| ( mask & Ctrl && !( modifiers.testFlag( Qt::ControlModifier ) ) )
|
||||
|| ( mask & Shift && !( modifiers.testFlag( Qt::ShiftModifier ) ) ) );
|
||||
}
|
||||
|
|
|
@ -15,13 +15,7 @@ public:
|
|||
Alt = 1,
|
||||
Ctrl = 2,
|
||||
Shift = 4,
|
||||
Win = 8, // Ironically, Linux only, since it's no use under Windows
|
||||
LeftAlt = 16, // Those Left-Right are Windows-only, at least for now
|
||||
RightAlt = 32,
|
||||
LeftCtrl = 64,
|
||||
RightCtrl = 128,
|
||||
LeftShift = 256,
|
||||
RightShift = 512
|
||||
Win = 8, // Ironically, Linux only, since it's no use under Windows
|
||||
};
|
||||
|
||||
/// Returns true if all Modifiers present within the given mask are pressed
|
||||
|
|
|
@ -478,7 +478,7 @@ void ArticleView::loadFinished( bool result )
|
|||
|
||||
void ArticleView::handleTitleChanged( QString const & title )
|
||||
{
|
||||
if ( !title.isEmpty() )
|
||||
if ( !title.isEmpty() && !title.contains( "://" ) )
|
||||
emit titleChanged( this, title );
|
||||
}
|
||||
|
||||
|
@ -1443,7 +1443,10 @@ void ArticleView::setContent( const QByteArray & data, const QString & mimeType,
|
|||
|
||||
QString ArticleView::getTitle()
|
||||
{
|
||||
return webview->page()->title();
|
||||
auto title = webview->title();
|
||||
if ( title.contains( "://" ) )
|
||||
return {};
|
||||
return webview->title();
|
||||
}
|
||||
|
||||
QString ArticleView::getWord() const
|
||||
|
@ -2125,8 +2128,8 @@ void ArticleView::highlightFTSResults()
|
|||
|
||||
QString script = QString(
|
||||
"var context = document.querySelector(\"body\");\n"
|
||||
"var instance = new Mark(context);\n"
|
||||
"instance.mark(\"%1\",{\"accuracy\": \"exactly\"});" )
|
||||
"var instance = new Mark(context);\n instance.unmark();\n"
|
||||
"instance.mark(\"%1\");" )
|
||||
.arg( regString );
|
||||
|
||||
webview->page()->runJavaScript( script );
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
#include <QMutexLocker>
|
||||
#include <memory>
|
||||
|
||||
#define AUTO_APPLY_LIMIT 150000
|
||||
|
||||
enum SearchType {
|
||||
FixedString,
|
||||
Wildcard,
|
||||
Regex
|
||||
};
|
||||
|
||||
DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary::Class * dict_ ):
|
||||
QDialog( parent ),
|
||||
cfg( cfg_ ),
|
||||
|
@ -55,6 +53,7 @@ DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary
|
|||
ui.matchCase->setChecked( cfg.headwordsDialog.matchCase );
|
||||
|
||||
model = std::make_shared< HeadwordListModel >();
|
||||
model->setMaxFilterResults( ui.filterMaxResult->value() );
|
||||
proxy = new QSortFilterProxyModel( this );
|
||||
|
||||
proxy->setSourceModel( model.get() );
|
||||
|
@ -75,6 +74,10 @@ DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary
|
|||
|
||||
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
||||
|
||||
//arbitrary number.
|
||||
bool exceedLimit = model->totalCount() > HEADWORDS_MAX_LIMIT;
|
||||
ui.filterMaxResult->setEnabled( exceedLimit );
|
||||
|
||||
connect( this, &QDialog::finished, this, &DictHeadwords::savePos );
|
||||
|
||||
if ( !fromMainWindow ) {
|
||||
|
@ -106,7 +109,6 @@ DictHeadwords::DictHeadwords( QWidget * parent, Config::Class & cfg_, Dictionary
|
|||
|
||||
connect( ui.headersListView, &QAbstractItemView::clicked, this, &DictHeadwords::itemClicked );
|
||||
|
||||
connect( proxy, &QAbstractItemModel::dataChanged, this, &DictHeadwords::showHeadwordsNumber );
|
||||
|
||||
ui.headersListView->installEventFilter( this );
|
||||
|
||||
|
@ -124,45 +126,46 @@ void DictHeadwords::setup( Dictionary::Class * dict_ )
|
|||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
dict = dict_;
|
||||
sortedWords.clear();
|
||||
|
||||
setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) );
|
||||
|
||||
const auto size = dict->getWordCount();
|
||||
std::shared_ptr< HeadwordListModel > other = std::make_shared< HeadwordListModel >();
|
||||
model.swap( other );
|
||||
model->setMaxFilterResults( ui.filterMaxResult->value() );
|
||||
model->setDict( dict );
|
||||
proxy->setSourceModel( model.get() );
|
||||
proxy->sort( 0 );
|
||||
filterChanged();
|
||||
|
||||
if ( size > AUTO_APPLY_LIMIT ) {
|
||||
cfg.headwordsDialog.autoApply = ui.autoApply->isChecked();
|
||||
ui.autoApply->setChecked( false );
|
||||
ui.autoApply->setEnabled( false );
|
||||
}
|
||||
else {
|
||||
ui.autoApply->setEnabled( true );
|
||||
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
||||
}
|
||||
ui.autoApply->setEnabled( true );
|
||||
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
||||
|
||||
ui.applyButton->setEnabled( !ui.autoApply->isChecked() );
|
||||
|
||||
//arbitrary number.
|
||||
bool exceedLimit = model->totalCount() > HEADWORDS_MAX_LIMIT;
|
||||
ui.filterMaxResult->setEnabled( exceedLimit );
|
||||
|
||||
setWindowIcon( dict->getIcon() );
|
||||
|
||||
dictId = QString( dict->getId().c_str() );
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
connect( model.get(), &HeadwordListModel::numberPopulated, this, [ this ]( int _ ) {
|
||||
showHeadwordsNumber();
|
||||
} );
|
||||
connect( proxy, &QAbstractItemModel::dataChanged, this, &DictHeadwords::showHeadwordsNumber );
|
||||
connect( ui.filterMaxResult, &QSpinBox::valueChanged, this, [ this ]( int _value ) {
|
||||
model->setMaxFilterResults( _value );
|
||||
} );
|
||||
}
|
||||
|
||||
void DictHeadwords::savePos()
|
||||
{
|
||||
cfg.headwordsDialog.searchMode = ui.searchModeCombo->currentIndex();
|
||||
cfg.headwordsDialog.matchCase = ui.matchCase->isChecked();
|
||||
|
||||
if ( model->totalCount() <= AUTO_APPLY_LIMIT )
|
||||
cfg.headwordsDialog.autoApply = ui.autoApply->isChecked();
|
||||
|
||||
cfg.headwordsDialog.autoApply = ui.autoApply->isChecked();
|
||||
cfg.headwordsDialog.headwordsDialogGeometry = saveGeometry();
|
||||
}
|
||||
|
||||
|
@ -255,18 +258,7 @@ void DictHeadwords::filterChanged()
|
|||
|
||||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
if ( sortedWords.isEmpty() && regExp.isValid() && !regExp.pattern().isEmpty() ) {
|
||||
const int headwordsNumber = model->totalCount();
|
||||
|
||||
QProgressDialog progress( tr( "Loading headwords..." ), tr( "Cancel" ), 0, headwordsNumber, this );
|
||||
progress.setWindowModality( Qt::WindowModal );
|
||||
loadAllSortedWords( progress );
|
||||
progress.close();
|
||||
}
|
||||
|
||||
const auto filtered = sortedWords.filter( regExp );
|
||||
|
||||
model->addMatches( filtered );
|
||||
model->setFilter( regExp );
|
||||
|
||||
proxy->setFilterRegularExpression( regExp );
|
||||
proxy->sort( 0 );
|
||||
|
@ -292,30 +284,44 @@ void DictHeadwords::autoApplyStateChanged( int state )
|
|||
|
||||
void DictHeadwords::showHeadwordsNumber()
|
||||
{
|
||||
ui.headersNumber->setText( tr( "Unique headwords total: %1, filtered: %2" )
|
||||
.arg( QString::number( model->totalCount() ), QString::number( proxy->rowCount() ) ) );
|
||||
if ( ui.filterLine->text().isEmpty() ) {
|
||||
ui.headersNumber->setText( tr( "Unique headwords total: %1." ).arg( QString::number( model->totalCount() ) ) );
|
||||
}
|
||||
else {
|
||||
ui.headersNumber->setText( tr( "Unique headwords total: %1, filtered(limited): %2" )
|
||||
.arg( QString::number( model->totalCount() ), QString::number( proxy->rowCount() ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void DictHeadwords::loadAllSortedWords( QProgressDialog & progress )
|
||||
void DictHeadwords::exportAllWords( QProgressDialog & progress, QTextStream & out )
|
||||
{
|
||||
if ( const QRegularExpression regExp = getFilterRegex(); regExp.isValid() && !regExp.pattern().isEmpty() ) {
|
||||
loadRegex( progress, out );
|
||||
return;
|
||||
}
|
||||
|
||||
const int headwordsNumber = model->totalCount();
|
||||
|
||||
QMutexLocker const _( &mutex );
|
||||
if ( sortedWords.isEmpty() ) {
|
||||
QSet< QString > allHeadwords;
|
||||
QSet< QString > allHeadwords;
|
||||
|
||||
int totalCount = 0;
|
||||
for ( int i = 0; i < headwordsNumber && i < model->wordCount(); ++i ) {
|
||||
if ( progress.wasCanceled() )
|
||||
break;
|
||||
progress.setValue( totalCount++ );
|
||||
int totalCount = 0;
|
||||
for ( int i = 0; i < headwordsNumber && i < model->wordCount(); ++i ) {
|
||||
if ( progress.wasCanceled() )
|
||||
break;
|
||||
|
||||
QVariant value = model->getRow( i );
|
||||
if ( !value.canConvert< QString >() )
|
||||
continue;
|
||||
QVariant value = model->getRow( i );
|
||||
if ( !value.canConvert< QString >() )
|
||||
continue;
|
||||
|
||||
allHeadwords.insert( value.toString() );
|
||||
}
|
||||
allHeadwords.insert( value.toString() );
|
||||
}
|
||||
|
||||
for ( const auto & item : allHeadwords ) {
|
||||
progress.setValue( totalCount++ );
|
||||
|
||||
writeWordToFile( out, item );
|
||||
}
|
||||
|
||||
// continue to write the remaining headword
|
||||
int nodeIndex = model->getCurrentIndex();
|
||||
|
@ -323,16 +329,42 @@ void DictHeadwords::loadAllSortedWords( QProgressDialog & progress )
|
|||
while ( !headwords.isEmpty() ) {
|
||||
if ( progress.wasCanceled() )
|
||||
break;
|
||||
allHeadwords.unite( headwords );
|
||||
|
||||
totalCount += headwords.size();
|
||||
progress.setValue( totalCount );
|
||||
for ( const auto & item : headwords ) {
|
||||
progress.setValue( totalCount++ );
|
||||
|
||||
writeWordToFile( out, item );
|
||||
}
|
||||
|
||||
|
||||
headwords = model->getRemainRows( nodeIndex );
|
||||
}
|
||||
}
|
||||
|
||||
sortedWords = allHeadwords.values();
|
||||
sortedWords.sort();
|
||||
void DictHeadwords::loadRegex( QProgressDialog & progress, QTextStream & out )
|
||||
{
|
||||
const int headwordsNumber = model->totalCount();
|
||||
|
||||
QMutexLocker const _( &mutex );
|
||||
QSet< QString > allHeadwords;
|
||||
|
||||
int totalCount = 0;
|
||||
for ( int i = 0; i < model->wordCount(); ++i ) {
|
||||
if ( progress.wasCanceled() )
|
||||
break;
|
||||
|
||||
QVariant value = model->getRow( i );
|
||||
if ( !value.canConvert< QString >() )
|
||||
continue;
|
||||
|
||||
allHeadwords.insert( value.toString() );
|
||||
}
|
||||
|
||||
progress.setMaximum( allHeadwords.size() );
|
||||
for ( const auto & item : allHeadwords ) {
|
||||
progress.setValue( totalCount++ );
|
||||
|
||||
writeWordToFile( out, item );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,11 +398,9 @@ void DictHeadwords::saveHeadersToFile()
|
|||
|
||||
const int headwordsNumber = model->totalCount();
|
||||
|
||||
QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber * 2, this );
|
||||
QProgressDialog progress( tr( "Export headwords..." ), tr( "Cancel" ), 0, headwordsNumber, this );
|
||||
progress.setWindowModality( Qt::WindowModal );
|
||||
|
||||
loadAllSortedWords( progress );
|
||||
|
||||
// Write UTF-8 BOM
|
||||
QTextStream out( &file );
|
||||
out.setGenerateByteOrderMark( true );
|
||||
|
@ -379,29 +409,7 @@ void DictHeadwords::saveHeadersToFile()
|
|||
out.setCodec( "UTF-8" );
|
||||
#endif
|
||||
|
||||
QStringList filtered;
|
||||
|
||||
if ( const QRegularExpression regExp = getFilterRegex(); regExp.isValid() && !regExp.pattern().isEmpty() ) {
|
||||
filtered = sortedWords.filter( regExp );
|
||||
}
|
||||
else {
|
||||
filtered = sortedWords;
|
||||
}
|
||||
auto currentValue = progress.value();
|
||||
// Write headwords
|
||||
for ( auto const & word : filtered ) {
|
||||
if ( progress.wasCanceled() )
|
||||
break;
|
||||
progress.setValue( currentValue++ );
|
||||
QByteArray line = word.toUtf8();
|
||||
|
||||
//usually the headword should not contain \r \n;
|
||||
line.replace( '\n', ' ' );
|
||||
line.replace( '\r', ' ' );
|
||||
|
||||
//write one line
|
||||
out << line << Qt::endl;
|
||||
}
|
||||
exportAllWords( progress, out );
|
||||
|
||||
file.close();
|
||||
|
||||
|
@ -412,8 +420,18 @@ void DictHeadwords::saveHeadersToFile()
|
|||
}
|
||||
else {
|
||||
//completed.
|
||||
progress.setValue( headwordsNumber * 2 );
|
||||
progress.close();
|
||||
QMessageBox::information( this, "GoldenDict", tr( "Export finished" ) );
|
||||
}
|
||||
}
|
||||
void DictHeadwords::writeWordToFile( QTextStream & out, const QString & word )
|
||||
{
|
||||
QByteArray line = word.toUtf8();
|
||||
|
||||
//usually the headword should not contain \r \n;
|
||||
line.replace( '\n', ' ' );
|
||||
line.replace( '\r', ' ' );
|
||||
|
||||
//write one line
|
||||
out << line << Qt::endl;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,10 @@ protected:
|
|||
|
||||
private:
|
||||
Ui::DictHeadwords ui;
|
||||
QStringList sortedWords;
|
||||
// QStringList sortedWords;
|
||||
QMutex mutex;
|
||||
static void writeWordToFile( QTextStream & out, const QString & word );
|
||||
|
||||
private slots:
|
||||
void savePos();
|
||||
void filterChangedInternal();
|
||||
|
@ -54,7 +56,8 @@ private slots:
|
|||
void itemClicked( const QModelIndex & index );
|
||||
void autoApplyStateChanged( int state );
|
||||
void showHeadwordsNumber();
|
||||
void loadAllSortedWords( QProgressDialog & progress );
|
||||
void exportAllWords( QProgressDialog & progress, QTextStream & out );
|
||||
void loadRegex( QProgressDialog & progress, QTextStream & out );
|
||||
virtual void reject();
|
||||
|
||||
signals:
|
||||
|
|
|
@ -101,6 +101,32 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="toolTip">
|
||||
<string>Specify the maximum filtered headwords returned.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Filter max results:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="filterMaxResult">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>3000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
|
|
@ -27,18 +27,6 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
|||
|
||||
connect( ui.showScanFlag, &QAbstractButton::toggled, this, &Preferences::showScanFlagToggled );
|
||||
|
||||
connect( ui.altKey, &QAbstractButton::clicked, this, &Preferences::wholeAltClicked );
|
||||
connect( ui.ctrlKey, &QAbstractButton::clicked, this, &Preferences::wholeCtrlClicked );
|
||||
connect( ui.shiftKey, &QAbstractButton::clicked, this, &Preferences::wholeShiftClicked );
|
||||
|
||||
connect( ui.leftAlt, &QAbstractButton::clicked, this, &Preferences::sideAltClicked );
|
||||
connect( ui.rightAlt, &QAbstractButton::clicked, this, &Preferences::sideAltClicked );
|
||||
connect( ui.leftCtrl, &QAbstractButton::clicked, this, &Preferences::sideCtrlClicked );
|
||||
connect( ui.rightCtrl, &QAbstractButton::clicked, this, &Preferences::sideCtrlClicked );
|
||||
connect( ui.leftShift, &QAbstractButton::clicked, this, &Preferences::sideShiftClicked );
|
||||
connect( ui.rightShift, &QAbstractButton::clicked, this, &Preferences::sideShiftClicked );
|
||||
|
||||
|
||||
helpAction.setShortcut( QKeySequence( "F1" ) );
|
||||
helpAction.setShortcutContext( Qt::WidgetWithChildrenShortcut );
|
||||
|
||||
|
@ -206,12 +194,6 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
|||
ui.ctrlKey->setChecked( p.scanPopupModifiers & KeyboardState::Ctrl );
|
||||
ui.shiftKey->setChecked( p.scanPopupModifiers & KeyboardState::Shift );
|
||||
ui.winKey->setChecked( p.scanPopupModifiers & KeyboardState::Win );
|
||||
ui.leftAlt->setChecked( p.scanPopupModifiers & KeyboardState::LeftAlt );
|
||||
ui.rightAlt->setChecked( p.scanPopupModifiers & KeyboardState::RightAlt );
|
||||
ui.leftCtrl->setChecked( p.scanPopupModifiers & KeyboardState::LeftCtrl );
|
||||
ui.rightCtrl->setChecked( p.scanPopupModifiers & KeyboardState::RightCtrl );
|
||||
ui.leftShift->setChecked( p.scanPopupModifiers & KeyboardState::LeftShift );
|
||||
ui.rightShift->setChecked( p.scanPopupModifiers & KeyboardState::RightShift );
|
||||
|
||||
ui.ignoreOwnClipboardChanges->setChecked( p.ignoreOwnClipboardChanges );
|
||||
ui.scanToMainWindow->setChecked( p.scanToMainWindow );
|
||||
|
@ -250,12 +232,6 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
|||
#ifdef Q_OS_WIN32
|
||||
ui.winKey->hide();
|
||||
#else
|
||||
ui.leftAlt->hide();
|
||||
ui.rightAlt->hide();
|
||||
ui.leftCtrl->hide();
|
||||
ui.rightCtrl->hide();
|
||||
ui.leftShift->hide();
|
||||
ui.rightShift->hide();
|
||||
#ifdef Q_OS_MAC
|
||||
ui.altKey->setText( "Opt" );
|
||||
ui.winKey->setText( "Ctrl" );
|
||||
|
@ -446,12 +422,6 @@ Config::Preferences Preferences::getPreferences()
|
|||
p.scanPopupModifiers += ui.ctrlKey->isChecked() ? KeyboardState::Ctrl : 0;
|
||||
p.scanPopupModifiers += ui.shiftKey->isChecked() ? KeyboardState::Shift : 0;
|
||||
p.scanPopupModifiers += ui.winKey->isChecked() ? KeyboardState::Win : 0;
|
||||
p.scanPopupModifiers += ui.leftAlt->isChecked() ? KeyboardState::LeftAlt : 0;
|
||||
p.scanPopupModifiers += ui.rightAlt->isChecked() ? KeyboardState::RightAlt : 0;
|
||||
p.scanPopupModifiers += ui.leftCtrl->isChecked() ? KeyboardState::LeftCtrl : 0;
|
||||
p.scanPopupModifiers += ui.rightCtrl->isChecked() ? KeyboardState::RightCtrl : 0;
|
||||
p.scanPopupModifiers += ui.leftShift->isChecked() ? KeyboardState::LeftShift : 0;
|
||||
p.scanPopupModifiers += ui.rightShift->isChecked() ? KeyboardState::RightShift : 0;
|
||||
|
||||
p.ignoreOwnClipboardChanges = ui.ignoreOwnClipboardChanges->isChecked();
|
||||
p.scanToMainWindow = ui.scanToMainWindow->isChecked();
|
||||
|
@ -556,48 +526,6 @@ void Preferences::showScanFlagToggled( bool b )
|
|||
ui.enableScanPopupModifiers->setChecked( false );
|
||||
}
|
||||
|
||||
|
||||
void Preferences::wholeAltClicked( bool b )
|
||||
{
|
||||
if ( b ) {
|
||||
ui.leftAlt->setChecked( false );
|
||||
ui.rightAlt->setChecked( false );
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences::wholeCtrlClicked( bool b )
|
||||
{
|
||||
if ( b ) {
|
||||
ui.leftCtrl->setChecked( false );
|
||||
ui.rightCtrl->setChecked( false );
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences::wholeShiftClicked( bool b )
|
||||
{
|
||||
if ( b ) {
|
||||
ui.leftShift->setChecked( false );
|
||||
ui.rightShift->setChecked( false );
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences::sideAltClicked( bool )
|
||||
{
|
||||
if ( ui.leftAlt->isChecked() || ui.rightAlt->isChecked() )
|
||||
ui.altKey->setChecked( false );
|
||||
}
|
||||
|
||||
void Preferences::sideCtrlClicked( bool )
|
||||
{
|
||||
if ( ui.leftCtrl->isChecked() || ui.rightCtrl->isChecked() )
|
||||
ui.ctrlKey->setChecked( false );
|
||||
}
|
||||
|
||||
void Preferences::sideShiftClicked( bool )
|
||||
{
|
||||
if ( ui.leftShift->isChecked() || ui.rightShift->isChecked() )
|
||||
ui.shiftKey->setChecked( false );
|
||||
}
|
||||
void Preferences::on_enableMainWindowHotkey_toggled( bool checked )
|
||||
{
|
||||
ui.mainWindowHotkey->setEnabled( checked );
|
||||
|
|
|
@ -41,14 +41,6 @@ private slots:
|
|||
void enableScanPopupModifiersToggled( bool );
|
||||
void showScanFlagToggled( bool b );
|
||||
|
||||
void wholeAltClicked( bool );
|
||||
void wholeCtrlClicked( bool );
|
||||
void wholeShiftClicked( bool );
|
||||
|
||||
void sideAltClicked( bool );
|
||||
void sideCtrlClicked( bool );
|
||||
void sideShiftClicked( bool );
|
||||
|
||||
void on_enableMainWindowHotkey_toggled( bool checked );
|
||||
void on_enableClipboardHotkey_toggled( bool checked );
|
||||
|
||||
|
|
|
@ -621,26 +621,6 @@ in the pressed state when the word selection changes.</string>
|
|||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="leftCtrl">
|
||||
<property name="toolTip">
|
||||
<string>Left Ctrl only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left Ctrl</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="rightShift">
|
||||
<property name="toolTip">
|
||||
<string>Right Shift only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="altKey">
|
||||
<property name="toolTip">
|
||||
|
@ -661,16 +641,6 @@ in the pressed state when the word selection changes.</string>
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="leftAlt">
|
||||
<property name="toolTip">
|
||||
<string>Left Alt only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="shiftKey">
|
||||
<property name="toolTip">
|
||||
|
@ -681,36 +651,6 @@ in the pressed state when the word selection changes.</string>
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="rightAlt">
|
||||
<property name="toolTip">
|
||||
<string>Right Alt only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right Alt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="rightCtrl">
|
||||
<property name="toolTip">
|
||||
<string>Right Ctrl only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right Ctrl</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="leftShift">
|
||||
<property name="toolTip">
|
||||
<string>Left Shift only</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QCheckBox" name="winKey">
|
||||
<property name="toolTip">
|
||||
|
@ -2035,15 +1975,9 @@ from Stardict, Babylon and GLS dictionaries</string>
|
|||
<tabstop>startToTray</tabstop>
|
||||
<tabstop>closeToTray</tabstop>
|
||||
<tabstop>cbAutostart</tabstop>
|
||||
<tabstop>leftCtrl</tabstop>
|
||||
<tabstop>rightShift</tabstop>
|
||||
<tabstop>altKey</tabstop>
|
||||
<tabstop>ctrlKey</tabstop>
|
||||
<tabstop>leftAlt</tabstop>
|
||||
<tabstop>shiftKey</tabstop>
|
||||
<tabstop>rightAlt</tabstop>
|
||||
<tabstop>rightCtrl</tabstop>
|
||||
<tabstop>leftShift</tabstop>
|
||||
<tabstop>winKey</tabstop>
|
||||
<tabstop>useProxyServer</tabstop>
|
||||
<tabstop>proxyType</tabstop>
|
||||
|
|
Loading…
Reference in a new issue