mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
fix: replace suggestion list with QCompleter (#808)
* fix: replace suggestionList with QCompleter
* 🎨 apply clang-format changes
* fix: code smells
---------
Co-authored-by: xiaoyifang <xiaoyifang@users.noreply.github.com>
This commit is contained in:
parent
32a583c16a
commit
671427803a
|
@ -409,7 +409,6 @@ HEADERS += \
|
|||
src/webmultimediadownload.hh \
|
||||
src/weburlrequestinterceptor.hh \
|
||||
src/wordfinder.hh \
|
||||
src/wordlist.hh \
|
||||
src/zipfile.hh \
|
||||
thirdparty/tomlplusplus/toml++/toml.h
|
||||
|
||||
|
@ -530,7 +529,6 @@ SOURCES += \
|
|||
src/webmultimediadownload.cc \
|
||||
src/weburlrequestinterceptor.cc \
|
||||
src/wordfinder.cc \
|
||||
src/wordlist.cc \
|
||||
src/zipfile.cc \
|
||||
thirdparty/fmt/format.cc
|
||||
|
||||
|
|
|
@ -220,16 +220,21 @@ class WordSearchRequestInstant: public WordSearchRequest
|
|||
public:
|
||||
|
||||
WordSearchRequestInstant()
|
||||
{ finish(); }
|
||||
{
|
||||
finish();
|
||||
}
|
||||
|
||||
virtual void cancel()
|
||||
{}
|
||||
void cancel() override {}
|
||||
|
||||
vector< WordMatch > & getMatches()
|
||||
{ return matches; }
|
||||
{
|
||||
return matches;
|
||||
}
|
||||
|
||||
void setUncertain( bool value )
|
||||
{ uncertain = value; }
|
||||
{
|
||||
uncertain = value;
|
||||
}
|
||||
};
|
||||
|
||||
/// A helper class for synchronous data read implementations.
|
||||
|
|
|
@ -123,7 +123,7 @@ MediaWikiWordSearchRequest::MediaWikiWordSearchRequest( wstring const & str,
|
|||
QNetworkAccessManager & mgr ) :
|
||||
isCancelling( false )
|
||||
{
|
||||
GD_DPRINTF( "request begin\n" );
|
||||
GD_DPRINTF( "wiki request begin\n" );
|
||||
QUrl reqUrl( url + "/api.php?action=query&list=allpages&aplimit=40&format=xml" );
|
||||
|
||||
GlobalBroadcaster::instance()->addWhitelist( reqUrl.host() );
|
||||
|
@ -188,8 +188,9 @@ void MediaWikiWordSearchRequest::downloadFinished()
|
|||
|
||||
QMutexLocker _( &dataMutex );
|
||||
|
||||
for( int x = 0; x < nl.length(); ++x )
|
||||
matches.push_back( gd::toWString( nl.item( x ).toElement().attribute( "title" ) ) );
|
||||
qDebug() << "matches" << matches.size();
|
||||
for ( int x = 0; x < nl.length(); ++x )
|
||||
matches.emplace_back( gd::toWString( nl.item( x ).toElement().attribute( "title" ) ) );
|
||||
}
|
||||
}
|
||||
GD_DPRINTF( "done.\n" );
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <QThreadPool>
|
||||
#include <QSslConfiguration>
|
||||
#include <QStyleFactory>
|
||||
#include "weburlrequestinterceptor.hh"
|
||||
#include "folding.hh"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
@ -46,6 +48,7 @@
|
|||
#include "help.hh"
|
||||
#include "ui_authentication.h"
|
||||
#include "resourceschemehandler.hh"
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#include "globalregex.hh"
|
||||
|
||||
|
@ -55,8 +58,6 @@
|
|||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include "wstring.hh"
|
||||
#include "wstring_qt.hh"
|
||||
#endif
|
||||
|
||||
#include <QWebEngineSettings>
|
||||
|
@ -315,22 +316,19 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
{
|
||||
groupList = groupListInDock;
|
||||
translateLine = ui.translateLine;
|
||||
wordList = ui.wordList;
|
||||
}
|
||||
else {
|
||||
groupList = groupListInToolbar;
|
||||
translateLine = translateBox->translateLine();
|
||||
wordList = translateBox->wordList();
|
||||
}
|
||||
wordList->attachFinder( &wordFinder );
|
||||
connect( &wordFinder, &WordFinder::updated, this, &MainWindow::prefixMatchUpdated );
|
||||
connect( &wordFinder, &WordFinder::finished, this, &MainWindow::prefixMatchFinished );
|
||||
|
||||
// for the old UI:
|
||||
ui.wordList->setTranslateLine( ui.translateLine );
|
||||
|
||||
groupList->setFocusPolicy( Qt::ClickFocus );
|
||||
wordList->setFocusPolicy( Qt::ClickFocus );
|
||||
ui.wordList->setFocusPolicy( Qt::ClickFocus );
|
||||
|
||||
wordListDefaultFont = wordList->font();
|
||||
wordListDefaultFont = ui.wordList->font();
|
||||
translateLineDefaultFont = translateLine->font();
|
||||
groupListDefaultFont = groupList->font();
|
||||
|
||||
|
@ -627,7 +625,7 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
|
||||
connect( ui.translateLine, &QLineEdit::textChanged, this, &MainWindow::translateInputChanged );
|
||||
|
||||
connect( translateBox->translateLine(), &QLineEdit::textChanged, this, &MainWindow::translateInputChanged );
|
||||
connect( translateBox->translateLine(), &QLineEdit::textEdited, this, &MainWindow::translateInputChanged );
|
||||
|
||||
connect( ui.translateLine, &QLineEdit::returnPressed, [ this ]() {
|
||||
translateInputFinished( true );
|
||||
|
@ -638,17 +636,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
|
||||
connect( ui.wordList, &QListWidget::itemSelectionChanged, this, &MainWindow::wordListSelectionChanged );
|
||||
|
||||
connect( translateBox->wordList(),
|
||||
SIGNAL( itemDoubleClicked( QListWidgetItem * ) ),
|
||||
this,
|
||||
SLOT( wordListItemActivated( QListWidgetItem * ) ) );
|
||||
|
||||
connect( ui.wordList, &QListWidget::itemClicked, this, &MainWindow::wordListItemActivated );
|
||||
|
||||
connect( ui.wordList, &WordList::statusBarMessage, this, &MainWindow::showStatusBarMessage );
|
||||
|
||||
connect( translateBox->wordList(), &WordList::statusBarMessage, this, &MainWindow::showStatusBarMessage );
|
||||
|
||||
connect( ui.dictsList, &QListWidget::itemSelectionChanged, this, &MainWindow::dictsListSelectionChanged );
|
||||
|
||||
connect( ui.dictsList, &QListWidget::itemDoubleClicked, this, &MainWindow::dictsListItemActivated );
|
||||
|
@ -661,10 +650,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
translateBox->translateLine()->installEventFilter( this );
|
||||
|
||||
ui.wordList->installEventFilter( this );
|
||||
translateBox->wordList()->installEventFilter( this );
|
||||
|
||||
ui.wordList->viewport()->installEventFilter( this );
|
||||
translateBox->wordList()->viewport()->installEventFilter( this );
|
||||
|
||||
ui.dictsList->installEventFilter( this );
|
||||
ui.dictsList->viewport()->installEventFilter( this );
|
||||
|
@ -889,6 +876,83 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
useSmallIconsInToolbarsTriggered();
|
||||
}
|
||||
|
||||
void MainWindow::prefixMatchUpdated()
|
||||
{
|
||||
updateMatchResults( false );
|
||||
}
|
||||
|
||||
void MainWindow::prefixMatchFinished()
|
||||
{
|
||||
updateMatchResults( true );
|
||||
}
|
||||
|
||||
void MainWindow::updateMatchResults( bool finished )
|
||||
{
|
||||
WordFinder::SearchResults const & results = wordFinder.getResults();
|
||||
|
||||
if ( cfg.preferences.searchInDock ) {
|
||||
ui.wordList->setUpdatesEnabled( false );
|
||||
//clear all existed items
|
||||
ui.wordList->clear();
|
||||
|
||||
for ( const auto & result : results ) {
|
||||
auto i = new QListWidgetItem( result.first, ui.wordList );
|
||||
i->setToolTip( result.first );
|
||||
|
||||
if ( result.second ) {
|
||||
QFont f = i->font();
|
||||
f.setItalic( true );
|
||||
i->setFont( f );
|
||||
}
|
||||
|
||||
i->setTextAlignment( Qt::AlignLeft );
|
||||
}
|
||||
|
||||
if ( ui.wordList->count() ) {
|
||||
ui.wordList->scrollToItem( ui.wordList->item( 0 ), QAbstractItemView::PositionAtTop );
|
||||
ui.wordList->setCurrentItem( nullptr, QItemSelectionModel::Clear );
|
||||
}
|
||||
|
||||
ui.wordList->setUpdatesEnabled( true );
|
||||
ui.wordList->unsetCursor();
|
||||
}
|
||||
else {
|
||||
|
||||
QStringList _results;
|
||||
_results.clear();
|
||||
|
||||
for ( const auto & result : results ) {
|
||||
_results << result.first;
|
||||
}
|
||||
translateBox->setModel( _results );
|
||||
}
|
||||
|
||||
if ( finished ) {
|
||||
|
||||
refreshTranslateLine();
|
||||
|
||||
if ( !wordFinder.getErrorString().isEmpty() )
|
||||
emit showStatusBarMessage( tr( "WARNING: %1" ).arg( wordFinder.getErrorString() ),
|
||||
20000,
|
||||
QPixmap( ":/icons/error.svg" ) );
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::refreshTranslateLine()
|
||||
{
|
||||
if ( !translateLine )
|
||||
return;
|
||||
|
||||
// Visually mark the input line to mark if there's no results
|
||||
bool setMark = wordFinder.getResults().empty() && !wordFinder.wasSearchUncertain();
|
||||
|
||||
if ( translateLine->property( "noResults" ).toBool() != setMark ) {
|
||||
translateLine->setProperty( "noResults", setMark );
|
||||
|
||||
Utils::Widget::setNoResultColor( translateLine, setMark );
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::clipboardChange( QClipboard::Mode m )
|
||||
{
|
||||
if ( !scanPopup ) {
|
||||
|
@ -963,9 +1027,10 @@ void MainWindow::updateSearchPaneAndBar( bool searchInDock )
|
|||
|
||||
groupList = groupListInDock;
|
||||
translateLine = ui.translateLine;
|
||||
wordList = ui.wordList;
|
||||
|
||||
translateBoxToolBarAction->setVisible( false );
|
||||
|
||||
translateBox->setPopupEnabled( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -988,7 +1053,6 @@ void MainWindow::updateSearchPaneAndBar( bool searchInDock )
|
|||
|
||||
groupList = groupListInToolbar;
|
||||
translateLine = translateBox->translateLine();
|
||||
wordList = translateBox->wordList();
|
||||
|
||||
translateBoxToolBarAction->setVisible( true );
|
||||
}
|
||||
|
@ -1003,8 +1067,6 @@ void MainWindow::updateSearchPaneAndBar( bool searchInDock )
|
|||
// reset the flag when switching UI modes
|
||||
wordListSelChanged = false;
|
||||
|
||||
wordList->attachFinder( &wordFinder );
|
||||
|
||||
updateGroupList();
|
||||
applyWordsZoomLevel();
|
||||
|
||||
|
@ -1014,7 +1076,6 @@ void MainWindow::updateSearchPaneAndBar( bool searchInDock )
|
|||
|
||||
void MainWindow::mousePressEvent( QMouseEvent * event )
|
||||
{
|
||||
|
||||
if ( handleBackForwardMouseButtons( event ) ) {
|
||||
return;
|
||||
}
|
||||
|
@ -2197,7 +2258,7 @@ void MainWindow::updateCurrentGroupProperty()
|
|||
|
||||
if ( grp && translateLine->property( "currentGroup" ).toString() != grp->name ) {
|
||||
translateLine->setProperty( "currentGroup", grp->name );
|
||||
wordList->setProperty( "currentGroup", grp->name );
|
||||
ui.wordList->setProperty( "currentGroup", grp->name );
|
||||
QString ss = styleSheet();
|
||||
|
||||
// Only update stylesheet if it mentions currentGroup, as updating the
|
||||
|
@ -2231,8 +2292,8 @@ void MainWindow::updateSuggestionList( QString const & newValue )
|
|||
// If some word is selected in the word list, unselect it. This prevents
|
||||
// triggering a set of spurious activation signals when the list changes.
|
||||
|
||||
if ( wordList->selectionModel()->hasSelection() )
|
||||
wordList->setCurrentItem( 0, QItemSelectionModel::Clear );
|
||||
if ( ui.wordList->selectionModel()->hasSelection() )
|
||||
ui.wordList->setCurrentItem( 0, QItemSelectionModel::Clear );
|
||||
|
||||
QString req = newValue.trimmed();
|
||||
|
||||
|
@ -2240,8 +2301,8 @@ void MainWindow::updateSuggestionList( QString const & newValue )
|
|||
{
|
||||
// An empty request always results in an empty result
|
||||
wordFinder.cancel();
|
||||
wordList->clear();
|
||||
wordList->unsetCursor();
|
||||
ui.wordList->clear();
|
||||
ui.wordList->unsetCursor();
|
||||
|
||||
// Reset the noResults mark if it's on right now
|
||||
if ( translateLine->property( "noResults" ).toBool() )
|
||||
|
@ -2253,8 +2314,7 @@ void MainWindow::updateSuggestionList( QString const & newValue )
|
|||
return;
|
||||
}
|
||||
|
||||
wordList->setCursor( Qt::WaitCursor );
|
||||
|
||||
ui.wordList->setCursor( Qt::WaitCursor );
|
||||
wordFinder.prefixMatch( req, getActiveDicts() );
|
||||
}
|
||||
|
||||
|
@ -2393,19 +2453,14 @@ bool MainWindow::eventFilter( QObject * obj, QEvent * ev )
|
|||
if ( ev->type() == QEvent::MouseButtonPress ) {
|
||||
QMouseEvent * event = static_cast< QMouseEvent * >( ev );
|
||||
|
||||
// clicks outside of the word list should hide it.
|
||||
if ( obj != translateBox->wordList() && obj != translateBox->wordList()->viewport() ) {
|
||||
translateBox->setPopupEnabled( false );
|
||||
}
|
||||
|
||||
return handleBackForwardMouseButtons( event );
|
||||
}
|
||||
|
||||
if ( ev->type() == QEvent::KeyPress ) {
|
||||
QKeyEvent * keyevent = static_cast< QKeyEvent * >( ev );
|
||||
auto keyevent = dynamic_cast< QKeyEvent * >( ev );
|
||||
|
||||
bool handleCtrlTab = ( obj == translateLine || obj == wordList || obj == ui.historyList || obj == ui.favoritesTree
|
||||
|| obj == ui.dictsList || obj == groupList );
|
||||
bool handleCtrlTab = ( obj == translateLine || obj == ui.wordList || obj == ui.historyList
|
||||
|| obj == ui.favoritesTree || obj == ui.dictsList || obj == groupList );
|
||||
|
||||
if ( keyevent->modifiers() == Qt::ControlModifier && keyevent->key() == Qt::Key_Tab ) {
|
||||
if ( cfg.preferences.mruTabOrder ) {
|
||||
|
@ -2436,10 +2491,10 @@ bool MainWindow::eventFilter( QObject * obj, QEvent * ev )
|
|||
|
||||
if ( cfg.preferences.searchInDock )
|
||||
{
|
||||
if ( keyEvent->matches( QKeySequence::MoveToNextLine ) && wordList->count() )
|
||||
if ( keyEvent->matches( QKeySequence::MoveToNextLine ) && ui.wordList->count() )
|
||||
{
|
||||
wordList->setFocus( Qt::ShortcutFocusReason );
|
||||
wordList->setCurrentRow( 0, QItemSelectionModel::ClearAndSelect );
|
||||
ui.wordList->setFocus( Qt::ShortcutFocusReason );
|
||||
ui.wordList->setCurrentRow( 0, QItemSelectionModel::ClearAndSelect );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2451,18 +2506,18 @@ bool MainWindow::eventFilter( QObject * obj, QEvent * ev )
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if ( obj == wordList ) {
|
||||
else if ( obj == ui.wordList ) {
|
||||
if ( ev->type() == QEvent::KeyPress ) {
|
||||
QKeyEvent * keyEvent = static_cast< QKeyEvent * >( ev );
|
||||
|
||||
if ( keyEvent->matches( QKeySequence::MoveToPreviousLine ) && !wordList->currentRow() ) {
|
||||
wordList->setCurrentRow( 0, QItemSelectionModel::Clear );
|
||||
if ( keyEvent->matches( QKeySequence::MoveToPreviousLine ) && !ui.wordList->currentRow() ) {
|
||||
ui.wordList->setCurrentRow( 0, QItemSelectionModel::Clear );
|
||||
translateLine->setFocus( Qt::ShortcutFocusReason );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( keyEvent->matches( QKeySequence::InsertParagraphSeparator ) &&
|
||||
wordList->selectedItems().size() )
|
||||
ui.wordList->selectedItems().size() )
|
||||
{
|
||||
if ( cfg.preferences.searchInDock )
|
||||
{
|
||||
|
@ -2508,7 +2563,7 @@ void MainWindow::wordListItemActivated( QListWidgetItem * item )
|
|||
|
||||
void MainWindow::wordListSelectionChanged()
|
||||
{
|
||||
QList< QListWidgetItem * > selected = wordList->selectedItems();
|
||||
QList< QListWidgetItem * > selected = ui.wordList->selectedItems();
|
||||
|
||||
if ( selected.size() )
|
||||
{
|
||||
|
@ -3438,8 +3493,8 @@ void MainWindow::applyWordsZoomLevel()
|
|||
font.setPointSize( ps );
|
||||
}
|
||||
|
||||
if ( wordList->font().pointSize() != ps )
|
||||
wordList->setFont( font );
|
||||
if ( ui.wordList->font().pointSize() != ps )
|
||||
ui.wordList->setFont( font );
|
||||
|
||||
font = translateLineDefaultFont;
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <QNetworkAccessManager>
|
||||
#include <QProgressDialog>
|
||||
#include "ui_mainwindow.h"
|
||||
#include "folding.hh"
|
||||
#include "config.hh"
|
||||
#include "dict/dictionary.hh"
|
||||
#include "article_netmgr.hh"
|
||||
|
@ -26,13 +25,11 @@
|
|||
#include "mainstatusbar.hh"
|
||||
#include "mruqmenu.hh"
|
||||
#include "translatebox.hh"
|
||||
#include "wordlist.hh"
|
||||
#include "dictheadwords.hh"
|
||||
#include "fulltextsearch.hh"
|
||||
#include "base_type.hh"
|
||||
|
||||
#include "hotkeywrapper.hh"
|
||||
#include "weburlrequestinterceptor.hh"
|
||||
#include "resourceschemehandler.hh"
|
||||
#include "iframeschemehandler.hh"
|
||||
#ifdef HAVE_X11
|
||||
|
@ -141,7 +138,7 @@ private:
|
|||
// in a separate thread
|
||||
AudioPlayerFactory audioPlayerFactory;
|
||||
|
||||
WordList * wordList;
|
||||
//current active translateLine;
|
||||
QLineEdit * translateLine;
|
||||
|
||||
WordFinder wordFinder;
|
||||
|
@ -462,7 +459,10 @@ private slots:
|
|||
void clipboardChange( QClipboard::Mode m );
|
||||
|
||||
void inspectElement( QWebEnginePage * );
|
||||
|
||||
void prefixMatchUpdated();
|
||||
void prefixMatchFinished();
|
||||
void updateMatchResults( bool finished );
|
||||
void refreshTranslateLine();
|
||||
signals:
|
||||
/// Retranslate Ctrl(Shift) + Click on dictionary pane to dictionary toolbar
|
||||
void clickOnDictPane( QString const & id );
|
||||
|
|
|
@ -192,7 +192,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="WordList" name="wordList"/>
|
||||
<widget class="QListWidget" name="wordList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -607,11 +607,6 @@
|
|||
<header>historypanewidget.hh</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>WordList</class>
|
||||
<extends>QListWidget</extends>
|
||||
<header>wordlist.hh</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>FavoritesPaneWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
|
|
|
@ -111,14 +111,12 @@ ScanPopup::ScanPopup( QWidget * parent,
|
|||
connect( definition, &ArticleView::sendWordToHistory, this, &ScanPopup::sendWordToHistory );
|
||||
connect( definition, &ArticleView::typingEvent, this, &ScanPopup::typingEvent );
|
||||
|
||||
wordListDefaultFont = ui.translateBox->wordList()->font();
|
||||
wordListDefaultFont = ui.translateBox->completerWidget()->font();
|
||||
translateLineDefaultFont = ui.translateBox->font();
|
||||
groupListDefaultFont = ui.groupList->font();
|
||||
|
||||
ui.mainLayout->addWidget( definition );
|
||||
|
||||
ui.translateBox->wordList()->attachFinder( &wordFinder );
|
||||
ui.translateBox->wordList()->setFocusPolicy(Qt::ClickFocus);
|
||||
ui.translateBox->translateLine()->installEventFilter( this );
|
||||
definition->installEventFilter(this);
|
||||
this->installEventFilter(this);
|
||||
|
@ -127,15 +125,6 @@ ScanPopup::ScanPopup( QWidget * parent,
|
|||
|
||||
connect( ui.translateBox->translateLine(), &QLineEdit::returnPressed, this, &ScanPopup::translateInputFinished );
|
||||
|
||||
connect( ui.translateBox->wordList(), &QListWidget::itemClicked, this, &ScanPopup::wordListItemActivated );
|
||||
|
||||
connect( ui.translateBox->wordList(),
|
||||
SIGNAL( itemDoubleClicked( QListWidgetItem * ) ),
|
||||
this,
|
||||
SLOT( wordListItemActivated( QListWidgetItem * ) ) );
|
||||
|
||||
connect( ui.translateBox->wordList(), &WordList::statusBarMessage, this, &ScanPopup::showStatusBarMessage );
|
||||
|
||||
ui.pronounceButton->setDisabled( true );
|
||||
|
||||
ui.groupList->fill( groups );
|
||||
|
@ -155,7 +144,7 @@ ScanPopup::ScanPopup( QWidget * parent,
|
|||
Config::Group * grp = cfg.getGroup( cfg.lastPopupGroupId );
|
||||
if( igrp && grp )
|
||||
igrp->checkMutedDictionaries( &grp->popupMutedDictionaries );
|
||||
dictionaryBar.setMutedDictionaries( grp ? &grp->popupMutedDictionaries : 0 );
|
||||
dictionaryBar.setMutedDictionaries( grp ? &grp->popupMutedDictionaries : nullptr );
|
||||
}
|
||||
|
||||
addToolBar( Qt::RightToolBarArea, &dictionaryBar );
|
||||
|
@ -280,10 +269,9 @@ ScanPopup::ScanPopup( QWidget * parent,
|
|||
#ifdef HAVE_X11
|
||||
scanFlag = new ScanFlag( this );
|
||||
|
||||
connect( scanFlag, &ScanFlag::requestScanPopup,
|
||||
this, [=]{
|
||||
connect( scanFlag, &ScanFlag::requestScanPopup, this, [ this ] {
|
||||
translateWordFromSelection();
|
||||
});
|
||||
} );
|
||||
|
||||
// Use delay show to prevent multiple popups while selection in progress
|
||||
selectionDelayTimer.setSingleShot( true );
|
||||
|
@ -362,11 +350,11 @@ void ScanPopup::applyWordsZoomLevel()
|
|||
font.setPointSize( ps );
|
||||
}
|
||||
|
||||
if ( ui.translateBox->wordList()->font().pointSize() != ps )
|
||||
ui.translateBox->wordList()->setFont( font );
|
||||
if ( ui.translateBox->completerWidget()->font().pointSize() != ps )
|
||||
ui.translateBox->completerWidget()->setFont( font );
|
||||
|
||||
font = translateLineDefaultFont;
|
||||
ps = font.pointSize();
|
||||
ps = font.pointSize();
|
||||
|
||||
if ( cfg.preferences.wordsZoomLevel != 0 )
|
||||
{
|
||||
|
@ -413,12 +401,12 @@ Qt::WindowFlags ScanPopup::unpinnedWindowFlags() const
|
|||
|
||||
void ScanPopup::translateWordFromClipboard()
|
||||
{
|
||||
return translateWordFromClipboard(QClipboard::Clipboard);
|
||||
return translateWordFromClipboard( QClipboard::Clipboard );
|
||||
}
|
||||
|
||||
void ScanPopup::translateWordFromSelection()
|
||||
{
|
||||
return translateWordFromClipboard(QClipboard::Selection);
|
||||
return translateWordFromClipboard( QClipboard::Selection );
|
||||
}
|
||||
|
||||
void ScanPopup::editGroupRequested()
|
||||
|
@ -627,7 +615,7 @@ void ScanPopup::currentGroupChanged( int )
|
|||
dictionaryBar.setMutedDictionaries( &grp->popupMutedDictionaries );
|
||||
}
|
||||
else
|
||||
dictionaryBar.setMutedDictionaries( 0 );
|
||||
dictionaryBar.setMutedDictionaries( nullptr );
|
||||
}
|
||||
|
||||
updateDictionaryBar();
|
||||
|
@ -641,11 +629,6 @@ void ScanPopup::currentGroupChanged( int )
|
|||
cfg.lastPopupGroupId = ui.groupList->getCurrentGroup();
|
||||
}
|
||||
|
||||
void ScanPopup::wordListItemActivated( QListWidgetItem * item )
|
||||
{
|
||||
showTranslationFor( item->text() );
|
||||
}
|
||||
|
||||
void ScanPopup::translateInputChanged( QString const & text )
|
||||
{
|
||||
updateSuggestionList( text );
|
||||
|
@ -659,7 +642,6 @@ void ScanPopup::updateSuggestionList()
|
|||
void ScanPopup::updateSuggestionList( QString const & text )
|
||||
{
|
||||
mainStatusBar->clearMessage();
|
||||
ui.translateBox->wordList()->setCurrentItem( 0, QItemSelectionModel::Clear );
|
||||
|
||||
QString req = text.trimmed();
|
||||
|
||||
|
@ -667,8 +649,6 @@ void ScanPopup::updateSuggestionList( QString const & text )
|
|||
{
|
||||
// An empty request always results in an empty result
|
||||
wordFinder.cancel();
|
||||
ui.translateBox->wordList()->clear();
|
||||
ui.translateBox->wordList()->unsetCursor();
|
||||
|
||||
// Reset the noResults mark if it's on right now
|
||||
if ( ui.translateBox->translateLine()->property( "noResults" ).toBool() )
|
||||
|
@ -681,8 +661,6 @@ void ScanPopup::updateSuggestionList( QString const & text )
|
|||
return;
|
||||
}
|
||||
|
||||
ui.translateBox->wordList()->setCursor( Qt::WaitCursor );
|
||||
|
||||
wordFinder.prefixMatch( req, getActiveDicts() );
|
||||
}
|
||||
|
||||
|
@ -959,9 +937,20 @@ void ScanPopup::prefixMatchFinished()
|
|||
{
|
||||
ui.queryError->setToolTip( wordFinder.getErrorString() );
|
||||
ui.queryError->show();
|
||||
showStatusBarMessage( tr( "WARNING: %1" ).arg( wordFinder.getErrorString() ),
|
||||
20000,
|
||||
QPixmap( ":/icons/error.svg" ) );
|
||||
}
|
||||
else
|
||||
else {
|
||||
ui.queryError->hide();
|
||||
auto results = wordFinder.getResults();
|
||||
QStringList _results;
|
||||
for ( auto const & [ fst, snd ] : results ) {
|
||||
_results << fst;
|
||||
}
|
||||
|
||||
ui.translateBox->setModel( _results );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1121,10 +1110,9 @@ void ScanPopup::updateDictionaryBar()
|
|||
|
||||
if( currentId == Instances::Group::AllGroupId )
|
||||
dictionaryBar.setMutedDictionaries( &cfg.popupMutedDictionaries );
|
||||
else
|
||||
{
|
||||
Config::Group * grp = cfg.getGroup( currentId );
|
||||
dictionaryBar.setMutedDictionaries( grp ? &grp->popupMutedDictionaries : 0 );
|
||||
else {
|
||||
Config::Group * group = cfg.getGroup( currentId );
|
||||
dictionaryBar.setMutedDictionaries( group ? &group->popupMutedDictionaries : nullptr );
|
||||
}
|
||||
|
||||
setDictionaryIconSize();
|
||||
|
|
|
@ -222,7 +222,6 @@ private slots:
|
|||
|
||||
void translateInputChanged(QString const & text);
|
||||
void translateInputFinished();
|
||||
void wordListItemActivated( QListWidgetItem * );
|
||||
|
||||
void focusTranslateLine();
|
||||
|
||||
|
|
|
@ -11,209 +11,50 @@
|
|||
#include <QModelIndex>
|
||||
#include <QScrollBar>
|
||||
#include <QStyle>
|
||||
|
||||
namespace
|
||||
{
|
||||
#define MAX_POPUP_ROWS 17
|
||||
}
|
||||
|
||||
CompletionList::CompletionList(TranslateBox * parent) : WordList(parent),
|
||||
translateBox(parent)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
setWindowFlags(Qt::ToolTip);
|
||||
#else
|
||||
setParent( parent->window() );
|
||||
setAutoFillBackground( true );
|
||||
#endif
|
||||
|
||||
connect( this, &QAbstractItemView::activated, this, &CompletionList::acceptCurrentEntry );
|
||||
|
||||
connect( this, &QListWidget::itemClicked, this, &CompletionList::acceptCurrentEntry );
|
||||
|
||||
translateBox->window()->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool CompletionList::eventFilter( QObject * obj, QEvent * ev )
|
||||
{
|
||||
// when the main window is moved or resized, hide the word list suggestions
|
||||
if ( obj != this && !isAncestorOf( qobject_cast< QWidget * >( obj ) )
|
||||
&& ( ev->type() == QEvent::Move || ev->type() == QEvent::Resize ) )
|
||||
{
|
||||
translateBox->setPopupEnabled( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
return QWidget::eventFilter( obj, ev );
|
||||
}
|
||||
|
||||
int CompletionList::preferredHeight() const
|
||||
{
|
||||
#if( QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
|
||||
const QSize itemSizeHint = itemDelegate()->sizeHint( viewOptions(), model()->index( 0, 0 ) );
|
||||
#else
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption( &option );
|
||||
const QSize itemSizeHint = itemDelegate()->sizeHint(option, model()->index( 0, 0 ) );
|
||||
#endif
|
||||
int rows = qMin( count(), MAX_POPUP_ROWS );
|
||||
|
||||
int scrollBarHeight = 0;
|
||||
|
||||
bool hBarIsVisible = horizontalScrollBar()->maximum() > 0;
|
||||
|
||||
if ( hBarIsVisible )
|
||||
scrollBarHeight += QApplication::style()->pixelMetric( QStyle::PM_ScrollBarExtent );
|
||||
|
||||
return rows == 0 ? 0 : itemSizeHint.height() * rows + frameWidth() * 2 + scrollBarHeight;
|
||||
}
|
||||
|
||||
bool CompletionList::acceptCurrentEntry()
|
||||
{
|
||||
if (!isVisible())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QModelIndex index = currentIndex();
|
||||
if ( !index.isValid() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
emit doubleClicked(index);
|
||||
translateBox->setPopupEnabled( false );
|
||||
|
||||
return true;
|
||||
}
|
||||
#include <QStringListModel>
|
||||
|
||||
TranslateBox::TranslateBox( QWidget * parent ):
|
||||
QWidget( parent ),
|
||||
word_list( new CompletionList( this ) ),
|
||||
translate_line( new QLineEdit( this ) ),
|
||||
m_popupEnabled( false )
|
||||
QWidget( parent ),
|
||||
translate_line( new QLineEdit( this ) ),
|
||||
m_popupEnabled( false )
|
||||
{
|
||||
// initially hidden
|
||||
word_list->hide();
|
||||
completer = new QCompleter( words, this );
|
||||
resize( 200, 90 );
|
||||
QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
|
||||
sizePolicy.setHorizontalStretch( 0 );
|
||||
sizePolicy.setVerticalStretch( 0 );
|
||||
setSizePolicy( sizePolicy );
|
||||
|
||||
resize(200, 90);
|
||||
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
setSizePolicy(sizePolicy);
|
||||
// setMinimumSize(QSize(800, 0));
|
||||
|
||||
setFocusProxy(translate_line);
|
||||
translate_line->setObjectName("translateLine");
|
||||
setFocusProxy( translate_line );
|
||||
translate_line->setObjectName( "translateLine" );
|
||||
translate_line->setPlaceholderText( tr( "Type a word or phrase to search dictionaries" ) );
|
||||
word_list->setTranslateLine(translate_line);
|
||||
|
||||
// completer = new QCompleter(m_completionList->model(), this);
|
||||
// completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
// completer->setCompletionMode(QCompleter::InlineCompletion);
|
||||
auto layout = new QHBoxLayout( this );
|
||||
setLayout( layout );
|
||||
layout->setContentsMargins( 0, 0, 0, 0 );
|
||||
layout->addWidget( translate_line );
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
setLayout(layout);
|
||||
layout->setContentsMargins(0,0,0,0);
|
||||
layout->addWidget(translate_line);
|
||||
auto dropdown = new QAction( QIcon( ":/icons/1downarrow.svg" ), tr( "Drop-down" ), this );
|
||||
connect( dropdown, &QAction::triggered, this, &TranslateBox::rightButtonClicked );
|
||||
|
||||
QAction * dropdown = new QAction( QIcon(":/icons/1downarrow.svg"), tr("Drop-down"),this);
|
||||
connect( dropdown,&QAction::triggered,this, &TranslateBox::rightButtonClicked );
|
||||
translate_line->addAction( dropdown, QLineEdit::TrailingPosition );
|
||||
translate_line->addAction( new QAction( QIcon( ":/icons/system-search.svg" ), "", this ),
|
||||
QLineEdit::LeadingPosition );
|
||||
|
||||
translate_line->addAction( dropdown,QLineEdit::TrailingPosition);
|
||||
translate_line->addAction( new QAction(QIcon(":/icons/system-search.svg"),"",this),QLineEdit::LeadingPosition);
|
||||
|
||||
translate_line->setFocusPolicy(Qt::ClickFocus);
|
||||
translate_line->setFocusPolicy( Qt::ClickFocus );
|
||||
|
||||
translate_line->installEventFilter( this );
|
||||
this->installEventFilter( this );
|
||||
|
||||
connect( translate_line, &QLineEdit::textChanged, this, &TranslateBox::onTextEdit );
|
||||
translate_line->setCompleter( completer );
|
||||
completer->setCompletionMode( QCompleter::UnfilteredPopupCompletion );
|
||||
completer->setMaxVisibleItems( 16 );
|
||||
|
||||
|
||||
connect( word_list, &WordList::contentChanged, this, &TranslateBox::showPopup );
|
||||
connect( completer, QOverload< const QString & >::of( &QCompleter::activated ), this, [ = ]( const QString & text ) {
|
||||
emit translate_line->returnPressed();
|
||||
} );
|
||||
}
|
||||
|
||||
bool TranslateBox::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
// hide the suggestions list when the window is not active
|
||||
if ( event->type() == QEvent::WindowDeactivate )
|
||||
{
|
||||
if (!word_list->isActiveWindow())
|
||||
{
|
||||
setPopupEnabled( false );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj == translate_line && event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_PageUp:
|
||||
case Qt::Key_PageDown:
|
||||
if ( !word_list->isVisible() )
|
||||
{
|
||||
setPopupEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
QApplication::sendEvent(word_list, event);
|
||||
}
|
||||
return true;
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
return word_list->acceptCurrentEntry();
|
||||
case Qt::Key_Escape:
|
||||
setPopupEnabled( false );
|
||||
return true;
|
||||
case Qt::Key_Tab:
|
||||
if ( !word_list->isVisible() )
|
||||
{
|
||||
setPopupEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
QKeyEvent event( QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier );
|
||||
QApplication::sendEvent( word_list, &event );
|
||||
}
|
||||
return true;
|
||||
case Qt::Key_Backtab:
|
||||
if ( !word_list->isVisible() )
|
||||
{
|
||||
setPopupEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
QKeyEvent event( QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier );
|
||||
QApplication::sendEvent( word_list, &event );
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (obj == translate_line && event->type() == QEvent::FocusOut) {
|
||||
#if defined(Q_OS_WIN)
|
||||
QFocusEvent *fev = static_cast<QFocusEvent*>(event);
|
||||
if (fev->reason() != Qt::ActiveWindowFocusReason ||
|
||||
(fev->reason() == Qt::ActiveWindowFocusReason && !word_list->isActiveWindow()))
|
||||
#endif
|
||||
setPopupEnabled( false );
|
||||
} else if (obj == translate_line && event->type() == QEvent::FocusIn) {
|
||||
// By default, focusing the traslate line does not show
|
||||
// the popup window.
|
||||
} else if (obj == this && event->type() == QEvent::ShortcutOverride) {
|
||||
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||
if (ke->key() == Qt::Key_Escape && !ke->modifiers() && word_list->isVisible() ) {
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void TranslateBox::setText( QString text, bool showPopup )
|
||||
void TranslateBox::setText( const QString & text, bool showPopup )
|
||||
{
|
||||
setPopupEnabled( showPopup );
|
||||
translate_line->setText( text );
|
||||
|
@ -232,56 +73,22 @@ void TranslateBox::setSizePolicy( QSizePolicy policy )
|
|||
translate_line->setSizePolicy( policy );
|
||||
}
|
||||
|
||||
void TranslateBox::setModel( QStringList & _words )
|
||||
{
|
||||
auto model = (QStringListModel *)( completer->model() );
|
||||
|
||||
model->setStringList( _words );
|
||||
}
|
||||
|
||||
void TranslateBox::showPopup()
|
||||
{
|
||||
// completer->setCompletionPrefix( m_fileLineEdit->text() );
|
||||
// qDebug() << "COMPLETION:" << completer->currentCompletion();
|
||||
|
||||
// Don't allow recursive call
|
||||
if( translateBoxMutex.tryLock() )
|
||||
translateBoxMutex.unlock();
|
||||
else
|
||||
return;
|
||||
QMutexLocker _( &translateBoxMutex );
|
||||
|
||||
if (translate_line->text().trimmed().isEmpty() || word_list->count() == 0)
|
||||
{
|
||||
// nothing to show
|
||||
if (word_list->isVisible())
|
||||
{
|
||||
word_list->hide();
|
||||
translate_line->setFocus();
|
||||
}
|
||||
return;
|
||||
if ( m_popupEnabled ) {
|
||||
completer->popup()->show();
|
||||
completer->complete();
|
||||
}
|
||||
|
||||
if ( !m_popupEnabled )
|
||||
{
|
||||
word_list->hide();
|
||||
return;
|
||||
else {
|
||||
completer->popup()->hide();
|
||||
}
|
||||
|
||||
int preferredHeight = word_list->preferredHeight();
|
||||
|
||||
QPoint origin( translate_line->x(), translate_line->y() + translate_line->height() );
|
||||
|
||||
if ( word_list->isWindow() )
|
||||
{
|
||||
origin = mapToGlobal( origin );
|
||||
}
|
||||
else
|
||||
{
|
||||
origin = mapTo( window(), origin );
|
||||
preferredHeight = qMin( translate_line->window()->height() - origin.y(), preferredHeight );
|
||||
}
|
||||
|
||||
const QSize size(width(), preferredHeight);
|
||||
const QRect rect( origin, size );
|
||||
|
||||
word_list->setGeometry(rect);
|
||||
word_list->show();
|
||||
word_list->raise();
|
||||
translate_line->setFocus();
|
||||
}
|
||||
|
||||
QLineEdit * TranslateBox::translateLine()
|
||||
|
@ -289,18 +96,16 @@ QLineEdit * TranslateBox::translateLine()
|
|||
return translate_line;
|
||||
}
|
||||
|
||||
WordList * TranslateBox::wordList()
|
||||
QWidget * TranslateBox::completerWidget()
|
||||
{
|
||||
return word_list;
|
||||
return completer->widget();
|
||||
}
|
||||
|
||||
void TranslateBox::rightButtonClicked()
|
||||
{
|
||||
setPopupEnabled( !m_popupEnabled );
|
||||
}
|
||||
|
||||
void TranslateBox::onTextEdit()
|
||||
void TranslateBox::setSizePolicy( QSizePolicy::Policy hor, QSizePolicy::Policy ver )
|
||||
{
|
||||
if ( translate_line->hasFocus() )
|
||||
setPopupEnabled( true );
|
||||
setSizePolicy( QSizePolicy( hor, ver ) );
|
||||
}
|
||||
|
|
|
@ -4,51 +4,25 @@
|
|||
#ifndef TRANSLATEBOX_HH
|
||||
#define TRANSLATEBOX_HH
|
||||
|
||||
#include "wordlist.hh"
|
||||
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QWidget>
|
||||
#include <QListWidget>
|
||||
#include <QFocusEvent>
|
||||
|
||||
class TranslateBox;
|
||||
|
||||
class CompletionList : public WordList
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CompletionList(TranslateBox * parent);
|
||||
int preferredHeight() const;
|
||||
virtual void setTranslateLine(QLineEdit * line)
|
||||
{
|
||||
WordList::setTranslateLine( line );
|
||||
setFocusProxy( line );
|
||||
}
|
||||
|
||||
public slots:
|
||||
bool acceptCurrentEntry();
|
||||
|
||||
private:
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
TranslateBox * translateBox;
|
||||
};
|
||||
#include <QCompleter>
|
||||
|
||||
class TranslateBox : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TranslateBox(QWidget * parent = 0);
|
||||
explicit TranslateBox( QWidget * parent = nullptr );
|
||||
QLineEdit * translateLine();
|
||||
WordList * wordList();
|
||||
void setText(QString text, bool showPopup=true);
|
||||
void setSizePolicy(QSizePolicy policy);
|
||||
inline void setSizePolicy(QSizePolicy::Policy hor, QSizePolicy::Policy ver)
|
||||
{ setSizePolicy(QSizePolicy(hor, ver)); }
|
||||
QWidget * completerWidget();
|
||||
void setText( const QString & text, bool showPopup = true );
|
||||
void setSizePolicy( QSizePolicy policy );
|
||||
void setSizePolicy( QSizePolicy::Policy hor, QSizePolicy::Policy ver );
|
||||
|
||||
signals:
|
||||
void setModel( QStringList & _words );
|
||||
|
||||
public slots:
|
||||
void setPopupEnabled(bool enable);
|
||||
|
@ -56,15 +30,12 @@ public slots:
|
|||
private slots:
|
||||
void showPopup();
|
||||
void rightButtonClicked();
|
||||
void onTextEdit();
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
CompletionList * word_list;
|
||||
QLineEdit * translate_line;
|
||||
bool m_popupEnabled;
|
||||
QMutex translateBoxMutex;
|
||||
// QCompleter * completer; // disabled for now
|
||||
QCompleter * completer;
|
||||
QStringList words;
|
||||
};
|
||||
|
||||
#endif // TRANSLATEBOX_HH
|
||||
|
|
|
@ -131,28 +131,23 @@ void WordFinder::startSearch()
|
|||
|
||||
allWordWritings[ 0 ] = gd::toWString( inputWord );
|
||||
|
||||
for( size_t x = 0; x < inputDicts->size(); ++x )
|
||||
{
|
||||
vector< wstring > writings = (*inputDicts)[ x ]->getAlternateWritings( allWordWritings[ 0 ] );
|
||||
for ( const auto & inputDict : *inputDicts ) {
|
||||
vector< wstring > writings = inputDict->getAlternateWritings( allWordWritings[ 0 ] );
|
||||
|
||||
allWordWritings.insert( allWordWritings.end(), writings.begin(), writings.end() );
|
||||
}
|
||||
|
||||
// Query each dictionary for all word writings
|
||||
|
||||
for( size_t x = 0; x < inputDicts->size(); ++x )
|
||||
{
|
||||
if ( ( (*inputDicts)[ x ]->getFeatures() & requestedFeatures ) != requestedFeatures )
|
||||
for ( const auto & inputDict : *inputDicts ) {
|
||||
if ( ( inputDict->getFeatures() & requestedFeatures ) != requestedFeatures )
|
||||
continue;
|
||||
|
||||
for( size_t y = 0; y < allWordWritings.size(); ++y )
|
||||
{
|
||||
try
|
||||
{
|
||||
sptr< Dictionary::WordSearchRequest > sr =
|
||||
( searchType == PrefixMatch || searchType == ExpressionMatch ) ?
|
||||
(*inputDicts)[ x ]->prefixMatch( allWordWritings[ y ], requestedMaxResults ) :
|
||||
(*inputDicts)[ x ]->stemmedMatch( allWordWritings[ y ], stemmedMinLength, stemmedMaxSuffixVariation, requestedMaxResults );
|
||||
for ( const auto & allWordWriting : allWordWritings ) {
|
||||
try {
|
||||
sptr< Dictionary::WordSearchRequest > sr = ( searchType == PrefixMatch || searchType == ExpressionMatch ) ?
|
||||
inputDict->prefixMatch( allWordWriting, requestedMaxResults ) :
|
||||
inputDict->stemmedMatch( allWordWriting, stemmedMinLength, stemmedMaxSuffixVariation, requestedMaxResults );
|
||||
|
||||
connect( sr.get(), &Dictionary::Request::finished, this, &WordFinder::requestFinished, Qt::QueuedConnection );
|
||||
|
||||
|
@ -161,7 +156,9 @@ void WordFinder::startSearch()
|
|||
catch( std::exception & e )
|
||||
{
|
||||
gdWarning( "Word \"%s\" search error (%s) in \"%s\"\n",
|
||||
inputWord.toUtf8().data(), e.what(), (*inputDicts)[ x ]->getName().c_str() );
|
||||
inputWord.toUtf8().data(),
|
||||
e.what(),
|
||||
inputDict->getName().c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,15 +188,12 @@ void WordFinder::requestFinished()
|
|||
bool newResults = false;
|
||||
|
||||
// See how many new requests have finished, and if we have any new results
|
||||
for( list< sptr< Dictionary::WordSearchRequest > >::iterator i =
|
||||
queuedRequests.begin(); i != queuedRequests.end(); )
|
||||
{
|
||||
if ( (*i)->isFinished() )
|
||||
{
|
||||
if ( searchInProgress && !(*i)->getErrorString().isEmpty() )
|
||||
for ( auto i = queuedRequests.begin(); i != queuedRequests.end(); ) {
|
||||
if ( ( *i )->isFinished() ) {
|
||||
if ( searchInProgress && !( *i )->getErrorString().isEmpty() )
|
||||
searchErrorString = tr( "Failed to query some dictionaries." );
|
||||
|
||||
if ( (*i)->isUncertain() )
|
||||
if ( ( *i )->isUncertain() )
|
||||
searchResultsUncertain = true;
|
||||
|
||||
if ( (*i)->matchesCount() )
|
||||
|
@ -233,8 +227,7 @@ void WordFinder::requestFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
if ( newResults && queuedRequests.size() && !updateResultsTimer.isActive() )
|
||||
{
|
||||
if ( newResults && !queuedRequests.empty() && !updateResultsTimer.isActive() ) {
|
||||
// If we have got some new results, but not all of them, we would start a
|
||||
// timer to update a user some time in the future
|
||||
updateResultsTimer.start();
|
||||
|
@ -297,17 +290,13 @@ void WordFinder::updateResults()
|
|||
|
||||
wstring original = Folding::applySimpleCaseOnly( allWordWritings[ 0 ] );
|
||||
|
||||
for( list< sptr< Dictionary::WordSearchRequest > >::iterator i =
|
||||
finishedRequests.begin(); i != finishedRequests.end(); )
|
||||
{
|
||||
for( size_t count = (*i)->matchesCount(), x = 0; x < count; ++x )
|
||||
{
|
||||
wstring match = (**i)[ x ].word;
|
||||
int weight = (**i)[ x ].weight;
|
||||
for ( auto i = finishedRequests.begin(); i != finishedRequests.end(); ) {
|
||||
for ( size_t count = ( *i )->matchesCount(), x = 0; x < count; ++x ) {
|
||||
wstring match = ( **i )[ x ].word;
|
||||
int weight = ( **i )[ x ].weight;
|
||||
wstring lowerCased = Folding::applySimpleCaseOnly( match );
|
||||
|
||||
if( searchType == ExpressionMatch )
|
||||
{
|
||||
if ( searchType == ExpressionMatch ) {
|
||||
unsigned ws;
|
||||
|
||||
for( ws = 0; ws < allWordWritings.size(); ws++ )
|
||||
|
@ -330,9 +319,8 @@ void WordFinder::updateResults()
|
|||
}
|
||||
weight = ws;
|
||||
}
|
||||
pair< ResultsIndex::iterator, bool > insertResult =
|
||||
resultsIndex.insert( pair< wstring, ResultsArray::iterator >( lowerCased,
|
||||
resultsArray.end() ) );
|
||||
auto insertResult =
|
||||
resultsIndex.insert( pair< wstring, ResultsArray::iterator >( lowerCased, resultsArray.end() ) );
|
||||
|
||||
if ( !insertResult.second )
|
||||
{
|
||||
|
@ -347,7 +335,7 @@ void WordFinder::updateResults()
|
|||
}
|
||||
else
|
||||
{
|
||||
resultsArray.push_back( OneResult() );
|
||||
resultsArray.emplace_back();
|
||||
|
||||
resultsArray.back().word = match;
|
||||
resultsArray.back().rank = INT_MAX;
|
||||
|
@ -361,14 +349,11 @@ void WordFinder::updateResults()
|
|||
|
||||
size_t maxSearchResults = 500;
|
||||
|
||||
if ( resultsArray.size() )
|
||||
{
|
||||
if ( searchType == PrefixMatch )
|
||||
{
|
||||
if ( !resultsArray.empty() ) {
|
||||
if ( searchType == PrefixMatch ) {
|
||||
/// Assign each result a category, storing it in the rank's field
|
||||
|
||||
enum Category
|
||||
{
|
||||
enum Category {
|
||||
ExactMatch,
|
||||
ExactNoFullCaseMatch,
|
||||
ExactNoDiaMatch,
|
||||
|
@ -385,63 +370,52 @@ void WordFinder::updateResults()
|
|||
Multiplier = 256 // Categories should be multiplied by Multiplier
|
||||
};
|
||||
|
||||
for( unsigned wr = 0; wr < allWordWritings.size(); ++wr )
|
||||
{
|
||||
wstring target = Folding::applySimpleCaseOnly( allWordWritings[ wr ] );
|
||||
for ( const auto & allWordWriting : allWordWritings ) {
|
||||
wstring target = Folding::applySimpleCaseOnly( allWordWriting );
|
||||
wstring targetNoFullCase = Folding::applyFullCaseOnly( target );
|
||||
wstring targetNoDia = Folding::applyDiacriticsOnly( targetNoFullCase );
|
||||
wstring targetNoPunct = Folding::applyPunctOnly( targetNoDia );
|
||||
wstring targetNoWs = Folding::applyWhitespaceOnly( targetNoPunct );
|
||||
wstring targetNoDia = Folding::applyDiacriticsOnly( targetNoFullCase );
|
||||
wstring targetNoPunct = Folding::applyPunctOnly( targetNoDia );
|
||||
wstring targetNoWs = Folding::applyWhitespaceOnly( targetNoPunct );
|
||||
|
||||
wstring::size_type matchPos = 0;
|
||||
|
||||
for( ResultsIndex::const_iterator i = resultsIndex.begin(), j = resultsIndex.end();
|
||||
i != j; ++i )
|
||||
{
|
||||
for ( const auto & i : resultsIndex ) {
|
||||
wstring resultNoFullCase, resultNoDia, resultNoPunct, resultNoWs;
|
||||
|
||||
int rank;
|
||||
|
||||
if ( i->first == target )
|
||||
if ( i.first == target )
|
||||
rank = ExactMatch * Multiplier;
|
||||
else
|
||||
if ( ( resultNoFullCase = Folding::applyFullCaseOnly( i->first ) ) == targetNoFullCase )
|
||||
else if ( ( resultNoFullCase = Folding::applyFullCaseOnly( i.first ) ) == targetNoFullCase )
|
||||
rank = ExactNoFullCaseMatch * Multiplier;
|
||||
else
|
||||
if ( ( resultNoDia = Folding::applyDiacriticsOnly( resultNoFullCase ) ) == targetNoDia )
|
||||
else if ( ( resultNoDia = Folding::applyDiacriticsOnly( resultNoFullCase ) ) == targetNoDia )
|
||||
rank = ExactNoDiaMatch * Multiplier;
|
||||
else
|
||||
if ( ( resultNoPunct = Folding::applyPunctOnly( resultNoDia ) ) == targetNoPunct )
|
||||
else if ( ( resultNoPunct = Folding::applyPunctOnly( resultNoDia ) ) == targetNoPunct )
|
||||
rank = ExactNoPunctMatch * Multiplier;
|
||||
else
|
||||
if ( ( resultNoWs = Folding::applyWhitespaceOnly( resultNoPunct ) ) == targetNoWs )
|
||||
else if ( ( resultNoWs = Folding::applyWhitespaceOnly( resultNoPunct ) ) == targetNoWs )
|
||||
rank = ExactNoWsMatch * Multiplier;
|
||||
else
|
||||
if ( hasSurroundedWithWs( i->first, target, matchPos ) )
|
||||
else if ( hasSurroundedWithWs( i.first, target, matchPos ) )
|
||||
rank = ExactInsideMatch * Multiplier + matchPos;
|
||||
else
|
||||
if ( hasSurroundedWithWs( resultNoDia, targetNoDia, matchPos ) )
|
||||
else if ( hasSurroundedWithWs( resultNoDia, targetNoDia, matchPos ) )
|
||||
rank = ExactNoDiaInsideMatch * Multiplier + matchPos;
|
||||
else
|
||||
if ( hasSurroundedWithWs( resultNoPunct, targetNoPunct, matchPos ) )
|
||||
else if ( hasSurroundedWithWs( resultNoPunct, targetNoPunct, matchPos ) )
|
||||
rank = ExactNoPunctInsideMatch * Multiplier + matchPos;
|
||||
else
|
||||
if ( i->first.size() > target.size() && i->first.compare( 0, target.size(), target ) == 0 )
|
||||
rank = PrefixMatch * Multiplier + saturated( i->first.size() );
|
||||
else
|
||||
if ( resultNoDia.size() > targetNoDia.size() && resultNoDia.compare( 0, targetNoDia.size(), targetNoDia ) == 0 )
|
||||
rank = PrefixNoDiaMatch * Multiplier + saturated( i->first.size() );
|
||||
else
|
||||
if ( resultNoPunct.size() > targetNoPunct.size() && resultNoPunct.compare( 0, targetNoPunct.size(), targetNoPunct ) == 0 )
|
||||
rank = PrefixNoPunctMatch * Multiplier + saturated( i->first.size() );
|
||||
else
|
||||
if ( resultNoWs.size() > targetNoWs.size() && resultNoWs.compare( 0, targetNoWs.size(), targetNoWs ) == 0 )
|
||||
rank = PrefixNoWsMatch * Multiplier + saturated( i->first.size() );
|
||||
else if ( i.first.size() > target.size() && i.first.compare( 0, target.size(), target ) == 0 )
|
||||
rank = PrefixMatch * Multiplier + saturated( i.first.size() );
|
||||
else if ( resultNoDia.size() > targetNoDia.size()
|
||||
&& resultNoDia.compare( 0, targetNoDia.size(), targetNoDia ) == 0 )
|
||||
rank = PrefixNoDiaMatch * Multiplier + saturated( i.first.size() );
|
||||
else if ( resultNoPunct.size() > targetNoPunct.size()
|
||||
&& resultNoPunct.compare( 0, targetNoPunct.size(), targetNoPunct ) == 0 )
|
||||
rank = PrefixNoPunctMatch * Multiplier + saturated( i.first.size() );
|
||||
else if ( resultNoWs.size() > targetNoWs.size()
|
||||
&& resultNoWs.compare( 0, targetNoWs.size(), targetNoWs ) == 0 )
|
||||
rank = PrefixNoWsMatch * Multiplier + saturated( i.first.size() );
|
||||
else
|
||||
rank = WorstMatch * Multiplier;
|
||||
|
||||
if ( i->second->rank > rank )
|
||||
i->second->rank = rank; // We store the best rank of any writing
|
||||
if ( i.second->rank > rank )
|
||||
i.second->rank = rank; // We store the best rank of any writing
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,26 +430,23 @@ void WordFinder::updateResults()
|
|||
// in their beginnings, and second, the length of the strings. Here we assign
|
||||
// only the first one, storing it in rank. Then we sort the results using
|
||||
// SortByRankAndLength.
|
||||
for( unsigned wr = 0; wr < allWordWritings.size(); ++wr )
|
||||
{
|
||||
wstring target = Folding::apply( allWordWritings[ wr ] );
|
||||
for ( const auto & allWordWriting : allWordWritings ) {
|
||||
wstring target = Folding::apply( allWordWriting );
|
||||
|
||||
for( ResultsIndex::const_iterator i = resultsIndex.begin(), j = resultsIndex.end();
|
||||
i != j; ++i )
|
||||
{
|
||||
wstring resultFolded = Folding::apply( i->first );
|
||||
for ( const auto & i : resultsIndex ) {
|
||||
wstring resultFolded = Folding::apply( i.first );
|
||||
|
||||
int charsInCommon = 0;
|
||||
|
||||
for( wchar const * t = target.c_str(), * r = resultFolded.c_str();
|
||||
*t && *t == *r; ++t, ++r, ++charsInCommon ) ;
|
||||
for ( wchar const *t = target.c_str(), *r = resultFolded.c_str(); *t && *t == *r; ++t, ++r, ++charsInCommon )
|
||||
;
|
||||
|
||||
int rank = -charsInCommon; // Negated so the lesser-than
|
||||
// comparison would yield right
|
||||
// results.
|
||||
|
||||
if ( i->second->rank > rank )
|
||||
i->second->rank = rank; // We store the best rank of any writing
|
||||
if ( i.second->rank > rank )
|
||||
i.second->rank = rank; // We store the best rank of any writing
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,24 +459,18 @@ void WordFinder::updateResults()
|
|||
searchResults.clear();
|
||||
searchResults.reserve( resultsArray.size() < maxSearchResults ? resultsArray.size() : maxSearchResults );
|
||||
|
||||
for( ResultsArray::const_iterator i = resultsArray.begin(), j = resultsArray.end();
|
||||
i != j; ++i )
|
||||
{
|
||||
//GD_DPRINTF( "%d: %ls\n", i->second, i->first.c_str() );
|
||||
|
||||
for ( const auto & i : resultsArray ) {
|
||||
if ( searchResults.size() < maxSearchResults )
|
||||
searchResults.push_back( std::pair< QString, bool >( QString::fromStdU32String( i->word ), i->wasSuggested ) );
|
||||
searchResults.emplace_back( QString::fromStdU32String( i.word ), i.wasSuggested );
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ( queuedRequests.size() )
|
||||
{
|
||||
if ( !queuedRequests.empty() ) {
|
||||
// There are still some unhandled results.
|
||||
emit updated();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// That were all of them.
|
||||
searchInProgress = false;
|
||||
emit finished();
|
||||
|
@ -514,8 +479,6 @@ void WordFinder::updateResults()
|
|||
|
||||
void WordFinder::cancelSearches()
|
||||
{
|
||||
for( list< sptr< Dictionary::WordSearchRequest > >::iterator i =
|
||||
queuedRequests.begin(); i != queuedRequests.end(); ++i )
|
||||
(*i)->cancel();
|
||||
for ( auto & queuedRequest : queuedRequests )
|
||||
queuedRequest->cancel();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,15 +22,14 @@ class WordFinder: public QObject
|
|||
|
||||
public:
|
||||
|
||||
typedef std::vector< std::pair< QString, bool > > SearchResults; // bool is a "was suggested" flag
|
||||
using SearchResults = std::vector< std::pair< QString, bool > >; // bool is a "was suggested" flag
|
||||
|
||||
private:
|
||||
|
||||
SearchResults searchResults;
|
||||
QString searchErrorString;
|
||||
bool searchResultsUncertain;
|
||||
std::list< sptr< Dictionary::WordSearchRequest > > queuedRequests,
|
||||
finishedRequests;
|
||||
std::list< sptr< Dictionary::WordSearchRequest > > queuedRequests, finishedRequests;
|
||||
bool searchInProgress;
|
||||
|
||||
QTimer updateResultsTimer;
|
||||
|
|
109
src/wordlist.cc
109
src/wordlist.cc
|
@ -1,109 +0,0 @@
|
|||
/* This file is (c) 2013 Tvangeste <i.4m.l33t@yandex.ru>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
|
||||
#include "wordlist.hh"
|
||||
|
||||
WordList::WordList( QWidget * parent ) : QListWidget( parent )
|
||||
, listItemDelegate( itemDelegate() )
|
||||
{
|
||||
wordFinder = 0;
|
||||
translateLine = 0;
|
||||
setItemDelegate( &listItemDelegate );
|
||||
}
|
||||
|
||||
void WordList::attachFinder( WordFinder * finder )
|
||||
{
|
||||
// qDebug() << "Attaching the word finder..." << finder;
|
||||
|
||||
if ( wordFinder == finder )
|
||||
return;
|
||||
|
||||
if ( wordFinder )
|
||||
{
|
||||
disconnect( wordFinder, &WordFinder::updated, this, &WordList::prefixMatchUpdated );
|
||||
disconnect( wordFinder, &WordFinder::finished, this, &WordList::prefixMatchFinished );
|
||||
}
|
||||
|
||||
wordFinder = finder;
|
||||
|
||||
connect( wordFinder, &WordFinder::updated, this, &WordList::prefixMatchUpdated );
|
||||
connect( wordFinder, &WordFinder::finished, this, &WordList::prefixMatchFinished );
|
||||
}
|
||||
|
||||
void WordList::prefixMatchUpdated()
|
||||
{
|
||||
updateMatchResults( false );
|
||||
}
|
||||
|
||||
void WordList::prefixMatchFinished()
|
||||
{
|
||||
updateMatchResults( true );
|
||||
}
|
||||
|
||||
void WordList::updateMatchResults( bool finished )
|
||||
{
|
||||
WordFinder::SearchResults const & results = wordFinder->getResults();
|
||||
|
||||
setUpdatesEnabled( false );
|
||||
//clear all existed items
|
||||
clear();
|
||||
|
||||
for( unsigned x = 0; x < results.size(); ++x )
|
||||
{
|
||||
QListWidgetItem * i = new QListWidgetItem( results[ x ].first, this );
|
||||
i->setToolTip( results[ x ].first );
|
||||
|
||||
if( results[ x ].second )
|
||||
{
|
||||
QFont f = i->font();
|
||||
f.setItalic( true );
|
||||
i->setFont( f );
|
||||
}
|
||||
|
||||
i->setTextAlignment( Qt::AlignLeft );
|
||||
}
|
||||
|
||||
if ( count() )
|
||||
{
|
||||
scrollToItem( item( 0 ), QAbstractItemView::PositionAtTop );
|
||||
setCurrentItem( 0, QItemSelectionModel::Clear );
|
||||
}
|
||||
|
||||
setUpdatesEnabled( true );
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
unsetCursor();
|
||||
|
||||
refreshTranslateLine();
|
||||
|
||||
if ( !wordFinder->getErrorString().isEmpty() )
|
||||
emit statusBarMessage(tr("WARNING: %1").arg(wordFinder->getErrorString()),
|
||||
20000, QPixmap(":/icons/error.svg"));
|
||||
}
|
||||
|
||||
if( !results.empty() && results.front().first.isRightToLeft() )
|
||||
setLayoutDirection( Qt::RightToLeft );
|
||||
else
|
||||
setLayoutDirection( Qt::LeftToRight );
|
||||
|
||||
emit contentChanged();
|
||||
}
|
||||
|
||||
void WordList::refreshTranslateLine()
|
||||
{
|
||||
if ( !translateLine )
|
||||
return;
|
||||
|
||||
// Visually mark the input line to mark if there's no results
|
||||
bool setMark = wordFinder->getResults().empty() && !wordFinder->wasSearchUncertain();
|
||||
|
||||
if ( translateLine->property( "noResults" ).toBool() != setMark )
|
||||
{
|
||||
translateLine->setProperty( "noResults", setMark );
|
||||
|
||||
Utils::Widget::setNoResultColor( translateLine, setMark );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/* This file is (c) 2013 Tvangeste <i.4m.l33t@yandex.ru>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#ifndef WORDLIST_HH
|
||||
#define WORDLIST_HH
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "wordfinder.hh"
|
||||
#include "delegate.hh"
|
||||
|
||||
class WordList : public QListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WordList(QWidget * parent = 0);
|
||||
void attachFinder(WordFinder * finder);
|
||||
virtual void setTranslateLine(QLineEdit * line)
|
||||
{ translateLine = line; }
|
||||
|
||||
protected:
|
||||
|
||||
signals:
|
||||
void statusBarMessage(QString const & message, int timeout = 0, QPixmap const & pixmap = QPixmap());
|
||||
void contentChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void prefixMatchUpdated();
|
||||
void prefixMatchFinished();
|
||||
void updateMatchResults( bool finished );
|
||||
|
||||
private:
|
||||
void refreshTranslateLine();
|
||||
|
||||
WordFinder * wordFinder;
|
||||
QLineEdit * translateLine;
|
||||
WordListItemDelegate listItemDelegate;
|
||||
|
||||
QVector< QSize > resizedSizes;
|
||||
};
|
||||
|
||||
#endif // WORDLIST_HH
|
Loading…
Reference in a new issue