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:
xiaoyifang 2023-06-05 21:22:20 +08:00 committed by GitHub
parent 32a583c16a
commit 671427803a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 286 additions and 661 deletions

View file

@ -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

View file

@ -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.

View file

@ -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" );

View file

@ -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;

View file

@ -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 );

View file

@ -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>

View file

@ -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();

View file

@ -222,7 +222,6 @@ private slots:
void translateInputChanged(QString const & text);
void translateInputFinished();
void wordListItemActivated( QListWidgetItem * );
void focusTranslateLine();

View file

@ -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 ) );
}

View file

@ -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

View file

@ -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,66 +370,55 @@ 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
}
}
resultsArray.sort( SortByRank() );
}
else
@ -456,29 +430,26 @@ 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( ResultsIndex::const_iterator i = resultsIndex.begin(), j = resultsIndex.end();
i != j; ++i )
{
wstring resultFolded = Folding::apply( i->first );
for ( const auto & allWordWriting : allWordWritings ) {
wstring target = Folding::apply( allWordWriting );
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
}
}
resultsArray.sort( SortByRankAndLength() );
maxSearchResults = 15;
@ -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();
}

View file

@ -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;

View file

@ -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 );
}
}

View file

@ -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