2012-02-20 21:47:14 +00:00
|
|
|
/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
|
2009-01-28 20:55:45 +00:00
|
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
|
|
|
|
#include "scanpopup.hh"
|
2009-02-01 00:08:08 +00:00
|
|
|
#include "folding.hh"
|
2009-02-02 20:28:53 +00:00
|
|
|
#include "mouseover.hh"
|
2009-04-18 17:20:12 +00:00
|
|
|
#include "wstring_qt.hh"
|
2009-01-28 20:55:45 +00:00
|
|
|
#include <QUrl>
|
2009-02-01 00:08:08 +00:00
|
|
|
#include <QCursor>
|
|
|
|
#include <QPixmap>
|
|
|
|
#include <QBitmap>
|
|
|
|
#include <QMenu>
|
2009-02-06 13:05:25 +00:00
|
|
|
#include <QMouseEvent>
|
2009-02-08 16:35:30 +00:00
|
|
|
#include <QDesktopWidget>
|
2011-06-19 18:50:11 +00:00
|
|
|
#include "dprintf.hh"
|
2009-02-01 00:08:08 +00:00
|
|
|
|
|
|
|
using std::wstring;
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2010-01-02 12:51:53 +00:00
|
|
|
/// We use different window flags under Windows and X11 due to slight differences
|
|
|
|
/// in their behavior on those platforms.
|
|
|
|
static Qt::WindowFlags popupWindowFlags =
|
|
|
|
|
|
|
|
#ifdef Q_WS_WIN
|
|
|
|
Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint
|
|
|
|
#else
|
|
|
|
Qt::Popup
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
|
2009-01-28 20:55:45 +00:00
|
|
|
ScanPopup::ScanPopup( QWidget * parent,
|
2009-02-06 17:04:11 +00:00
|
|
|
Config::Class & cfg_,
|
2009-02-05 20:55:00 +00:00
|
|
|
ArticleNetworkAccessManager & articleNetMgr,
|
2009-02-01 00:08:08 +00:00
|
|
|
std::vector< sptr< Dictionary::Class > > const & allDictionaries_,
|
2009-10-21 19:37:07 +00:00
|
|
|
Instances::Groups const & groups_,
|
|
|
|
History & history_ ):
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow( parent ),
|
2009-02-05 20:55:00 +00:00
|
|
|
cfg( cfg_ ),
|
2009-02-08 20:20:02 +00:00
|
|
|
isScanningEnabled( false ),
|
2009-02-01 00:08:08 +00:00
|
|
|
allDictionaries( allDictionaries_ ),
|
|
|
|
groups( groups_ ),
|
2009-10-21 19:37:07 +00:00
|
|
|
history( history_ ),
|
2009-05-16 11:14:43 +00:00
|
|
|
escapeAction( this ),
|
2009-02-06 13:05:25 +00:00
|
|
|
wordFinder( this ),
|
2010-03-30 20:15:55 +00:00
|
|
|
dictionaryBar( this, cfg.popupMutedDictionaries, configEvents ),
|
2010-01-02 23:26:09 +00:00
|
|
|
mouseEnteredOnce( false ),
|
|
|
|
mouseIntercepted( false ),
|
2009-04-10 13:56:38 +00:00
|
|
|
hideTimer( this )
|
2009-01-28 20:55:45 +00:00
|
|
|
{
|
|
|
|
ui.setupUi( this );
|
2009-03-26 19:00:08 +00:00
|
|
|
|
2011-07-14 08:17:59 +00:00
|
|
|
mainStatusBar = new MainStatusBar( this );
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
ui.queryError->hide();
|
|
|
|
|
2009-04-12 16:22:42 +00:00
|
|
|
definition = new ArticleView( ui.outerFrame, articleNetMgr, allDictionaries,
|
2010-03-30 20:15:55 +00:00
|
|
|
groups, true, cfg,
|
|
|
|
dictionaryBar.toggleViewAction(),
|
|
|
|
&cfg.popupMutedDictionaries );
|
2009-04-30 20:20:05 +00:00
|
|
|
|
|
|
|
applyZoomFactor();
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
ui.mainLayout->addWidget( definition );
|
|
|
|
|
2009-04-10 15:52:08 +00:00
|
|
|
ui.wordListButton->hide();
|
2009-04-10 21:07:03 +00:00
|
|
|
ui.pronounceButton->hide();
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
ui.groupList->fill( groups );
|
2009-04-10 12:48:40 +00:00
|
|
|
ui.groupList->setCurrentGroup( cfg.lastPopupGroupId );
|
2009-02-06 17:04:11 +00:00
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
dictionaryBar.setFloatable( false );
|
|
|
|
|
|
|
|
addToolBar( Qt::RightToolBarArea, &dictionaryBar );
|
|
|
|
|
2010-05-08 14:01:59 +00:00
|
|
|
connect( &dictionaryBar, SIGNAL(editGroupRequested()),
|
|
|
|
this, SLOT(editGroupRequested()) );
|
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
if ( cfg.popupWindowGeometry.size() )
|
|
|
|
restoreGeometry( cfg.popupWindowGeometry );
|
|
|
|
|
|
|
|
if ( cfg.popupWindowState.size() )
|
|
|
|
restoreState( cfg.popupWindowState, 1 );
|
|
|
|
|
2011-05-01 23:52:11 +00:00
|
|
|
ui.pinButton->setChecked( cfg.pinPopupWindow );
|
|
|
|
|
|
|
|
if ( cfg.pinPopupWindow )
|
|
|
|
{
|
|
|
|
dictionaryBar.setMovable( true );
|
|
|
|
setWindowFlags( Qt::Dialog );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dictionaryBar.setMovable( false );
|
|
|
|
setWindowFlags( popupWindowFlags );
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
connect( &configEvents, SIGNAL( mutedDictionariesChanged() ),
|
|
|
|
this, SLOT( mutedDictionariesChanged() ) );
|
2009-02-06 17:16:33 +00:00
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
definition->focus();
|
2009-02-06 13:05:25 +00:00
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
#if 0 // Experimental code to give window a non-rectangular shape (i.e.
|
|
|
|
// balloon) using a colorkey mask.
|
|
|
|
QPixmap pixMask( size() );
|
|
|
|
render( &pixMask );
|
|
|
|
|
|
|
|
setMask( pixMask.createMaskFromColor( QColor( 255, 0, 0 ) ) );
|
|
|
|
|
|
|
|
// This helps against flickering
|
|
|
|
setAttribute( Qt::WA_NoSystemBackground );
|
|
|
|
#endif
|
|
|
|
|
2009-05-16 11:14:43 +00:00
|
|
|
escapeAction.setShortcut( QKeySequence( "Esc" ) );
|
|
|
|
addAction( &escapeAction );
|
|
|
|
connect( &escapeAction, SIGNAL( triggered() ),
|
|
|
|
this, SLOT( escapePressed() ) );
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
connect( ui.groupList, SIGNAL( currentIndexChanged( QString const & ) ),
|
|
|
|
this, SLOT( currentGroupChanged( QString const & ) ) );
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
connect( &wordFinder, SIGNAL( finished() ),
|
|
|
|
this, SLOT( prefixMatchFinished() ) );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
connect( ui.pinButton, SIGNAL( clicked( bool ) ),
|
|
|
|
this, SLOT( pinButtonClicked( bool ) ) );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-05-14 19:42:04 +00:00
|
|
|
connect( definition, SIGNAL( pageLoaded( ArticleView * ) ),
|
|
|
|
this, SLOT( pageLoaded( ArticleView * ) ) );
|
2009-04-10 21:07:03 +00:00
|
|
|
|
2011-07-14 20:11:57 +00:00
|
|
|
connect( definition, SIGNAL( statusBarMessage( QString const &, int, QPixmap const & ) ),
|
|
|
|
this, SLOT( showStatusBarMessage( QString const &, int, QPixmap const & ) ) );
|
2011-07-14 08:17:59 +00:00
|
|
|
|
2009-01-28 20:55:45 +00:00
|
|
|
connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ),
|
|
|
|
this, SLOT( clipboardChanged( QClipboard::Mode ) ) );
|
2009-02-02 20:28:53 +00:00
|
|
|
|
|
|
|
connect( &MouseOver::instance(), SIGNAL( hovered( QString const & ) ),
|
|
|
|
this, SLOT( mouseHovered( QString const & ) ) );
|
2009-04-10 13:56:38 +00:00
|
|
|
|
|
|
|
hideTimer.setSingleShot( true );
|
|
|
|
hideTimer.setInterval( 400 );
|
|
|
|
|
|
|
|
connect( &hideTimer, SIGNAL( timeout() ),
|
|
|
|
this, SLOT( hideTimerExpired() ) );
|
2009-04-11 16:44:14 +00:00
|
|
|
|
|
|
|
altModeExpirationTimer.setSingleShot( true );
|
|
|
|
altModeExpirationTimer.setInterval( cfg.preferences.scanPopupAltModeSecs * 1000 );
|
|
|
|
|
|
|
|
connect( &altModeExpirationTimer, SIGNAL( timeout() ),
|
|
|
|
this, SLOT( altModeExpired() ) );
|
|
|
|
|
|
|
|
// This one polls constantly for modifiers while alt mode lasts
|
|
|
|
altModePollingTimer.setSingleShot( false );
|
|
|
|
altModePollingTimer.setInterval( 50 );
|
|
|
|
connect( &altModePollingTimer, SIGNAL( timeout() ),
|
|
|
|
this, SLOT( altModePoll() ) );
|
2010-07-03 16:24:30 +00:00
|
|
|
|
|
|
|
mouseGrabPollTimer.setSingleShot( false );
|
|
|
|
mouseGrabPollTimer.setInterval( 10 );
|
|
|
|
connect( &mouseGrabPollTimer, SIGNAL( timeout() ),
|
|
|
|
this, SLOT(mouseGrabPoll()) );
|
2011-06-17 12:15:41 +00:00
|
|
|
|
2011-07-28 13:04:06 +00:00
|
|
|
MouseOver::instance().setPreferencesPtr( &( cfg.preferences ) );
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2009-02-08 20:20:02 +00:00
|
|
|
ScanPopup::~ScanPopup()
|
|
|
|
{
|
2011-05-01 23:52:11 +00:00
|
|
|
// Save state, geometry and pin status
|
2010-03-30 20:15:55 +00:00
|
|
|
cfg.popupWindowState = saveState( 1 );
|
|
|
|
cfg.popupWindowGeometry = saveGeometry();
|
2011-05-01 23:52:11 +00:00
|
|
|
cfg.pinPopupWindow = ui.pinButton->isChecked();
|
2010-03-30 20:15:55 +00:00
|
|
|
|
2009-02-08 20:20:02 +00:00
|
|
|
disableScanning();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::enableScanning()
|
|
|
|
{
|
|
|
|
if ( !isScanningEnabled )
|
|
|
|
{
|
|
|
|
isScanningEnabled = true;
|
|
|
|
MouseOver::instance().enableMouseOver();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::disableScanning()
|
|
|
|
{
|
|
|
|
if ( isScanningEnabled )
|
|
|
|
{
|
|
|
|
MouseOver::instance().disableMouseOver();
|
|
|
|
isScanningEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-30 20:20:05 +00:00
|
|
|
void ScanPopup::applyZoomFactor()
|
|
|
|
{
|
|
|
|
definition->setZoomFactor( cfg.preferences.zoomFactor );
|
|
|
|
}
|
|
|
|
|
2009-04-21 18:27:26 +00:00
|
|
|
void ScanPopup::translateWordFromClipboard()
|
|
|
|
{
|
2009-07-31 11:40:54 +00:00
|
|
|
return translateWordFromClipboard(QClipboard::Clipboard);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::translateWordFromSelection()
|
|
|
|
{
|
|
|
|
return translateWordFromClipboard(QClipboard::Selection);
|
|
|
|
}
|
|
|
|
|
2010-05-08 14:01:59 +00:00
|
|
|
void ScanPopup::editGroupRequested()
|
|
|
|
{
|
|
|
|
emit editGroupRequested( ui.groupList->getCurrentGroup() );
|
|
|
|
}
|
|
|
|
|
2009-07-31 11:40:54 +00:00
|
|
|
void ScanPopup::translateWordFromClipboard(QClipboard::Mode m)
|
|
|
|
{
|
2011-06-19 18:50:11 +00:00
|
|
|
DPRINTF( "translating from clipboard or selection\n" );
|
2009-04-21 18:27:26 +00:00
|
|
|
|
|
|
|
QString subtype = "plain";
|
|
|
|
|
2009-07-31 11:40:54 +00:00
|
|
|
QString str = QApplication::clipboard()->text( subtype, m);
|
2009-04-21 18:27:26 +00:00
|
|
|
|
2011-11-16 13:02:56 +00:00
|
|
|
translateWord( str );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::translateWord( QString const & word )
|
|
|
|
{
|
|
|
|
QString str = pendingInputWord = gd::toQString( Folding::trimWhitespaceOrPunct( gd::toWString( word ) ) );
|
2009-04-21 18:27:26 +00:00
|
|
|
|
|
|
|
if ( !str.size() )
|
|
|
|
return; // Nothing there
|
|
|
|
|
|
|
|
// In case we had any timers engaged before, cancel them now.
|
|
|
|
altModePollingTimer.stop();
|
|
|
|
altModeExpirationTimer.stop();
|
|
|
|
|
|
|
|
inputWord = str;
|
2010-01-02 23:26:09 +00:00
|
|
|
engagePopup(
|
|
|
|
#ifdef Q_WS_WIN
|
|
|
|
true // We only focus popup under Windows when activated via Ctrl+C+C
|
|
|
|
// -- on Linux it already has an implicit focus
|
|
|
|
#endif
|
|
|
|
);
|
2009-04-21 18:27:26 +00:00
|
|
|
}
|
|
|
|
|
2009-01-28 20:55:45 +00:00
|
|
|
void ScanPopup::clipboardChanged( QClipboard::Mode m )
|
|
|
|
{
|
2009-02-08 20:20:02 +00:00
|
|
|
if ( !isScanningEnabled )
|
|
|
|
return;
|
|
|
|
|
2011-06-19 18:50:11 +00:00
|
|
|
DPRINTF( "clipboard changed\n" );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
QString subtype = "plain";
|
|
|
|
|
2009-02-02 20:28:53 +00:00
|
|
|
handleInputWord( QApplication::clipboard()->text( subtype, m ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::mouseHovered( QString const & str )
|
|
|
|
{
|
|
|
|
handleInputWord( str );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::handleInputWord( QString const & str )
|
|
|
|
{
|
2010-12-03 20:10:18 +00:00
|
|
|
QString sanitizedStr = gd::toQString( Folding::trimWhitespaceOrPunct( gd::toWString( str ) ) );
|
|
|
|
|
|
|
|
if ( isVisible() && sanitizedStr == inputWord )
|
|
|
|
{
|
|
|
|
// Attempt to translate the same word we already have shown in scan popup.
|
|
|
|
// Ignore it, as it is probably a spurious mouseover event.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pendingInputWord = sanitizedStr;
|
2009-02-05 16:56:57 +00:00
|
|
|
|
2009-04-11 16:44:14 +00:00
|
|
|
if ( !pendingInputWord.size() )
|
|
|
|
{
|
|
|
|
if ( cfg.preferences.scanPopupAltMode )
|
|
|
|
{
|
|
|
|
// In case we had any timers engaged before, cancel them now, since
|
|
|
|
// we're not going to translate anything anymore.
|
|
|
|
altModePollingTimer.stop();
|
|
|
|
altModeExpirationTimer.stop();
|
|
|
|
}
|
2009-02-05 16:56:57 +00:00
|
|
|
return;
|
2009-04-11 16:44:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check key modifiers
|
2009-02-05 16:56:57 +00:00
|
|
|
|
2009-04-11 16:44:14 +00:00
|
|
|
if ( cfg.preferences.enableScanPopupModifiers && !checkModifiersPressed( cfg.preferences.scanPopupModifiers ) )
|
|
|
|
{
|
|
|
|
if ( cfg.preferences.scanPopupAltMode )
|
|
|
|
{
|
|
|
|
altModePollingTimer.start();
|
|
|
|
altModeExpirationTimer.start();
|
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
return;
|
2009-04-11 16:44:14 +00:00
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-04-11 16:44:14 +00:00
|
|
|
inputWord = pendingInputWord;
|
|
|
|
engagePopup();
|
|
|
|
}
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
void ScanPopup::engagePopup( bool giveFocus )
|
2009-04-11 16:44:14 +00:00
|
|
|
{
|
2011-11-16 12:52:25 +00:00
|
|
|
if( cfg.preferences.scanToMainWindow )
|
|
|
|
{
|
|
|
|
// Send translated word to main window istead of show popup
|
|
|
|
emit sendWordToMainWindow( inputWord );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-05 20:55:00 +00:00
|
|
|
/// Too large strings make window expand which is probably not what user
|
|
|
|
/// wants
|
|
|
|
ui.word->setText( elideInputWord() );
|
2009-12-27 12:00:59 +00:00
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
if ( !isVisible() )
|
|
|
|
{
|
2009-12-27 12:00:59 +00:00
|
|
|
// Need to show the window
|
2009-02-08 16:35:30 +00:00
|
|
|
|
2009-12-27 12:00:59 +00:00
|
|
|
if ( !ui.pinButton->isChecked() )
|
|
|
|
{
|
|
|
|
// Decide where should the window land
|
|
|
|
|
|
|
|
QPoint currentPos = QCursor::pos();
|
|
|
|
|
|
|
|
QRect desktop = QApplication::desktop()->screenGeometry();
|
|
|
|
|
|
|
|
QSize windowSize = geometry().size();
|
|
|
|
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
/// Try the to-the-right placement
|
|
|
|
if ( currentPos.x() + 4 + windowSize.width() <= desktop.topRight().x() )
|
|
|
|
x = currentPos.x() + 4;
|
|
|
|
else
|
|
|
|
/// Try the to-the-left placement
|
|
|
|
if ( currentPos.x() - 4 - windowSize.width() >= desktop.x() )
|
|
|
|
x = currentPos.x() - 4 - windowSize.width();
|
|
|
|
else
|
|
|
|
// Center it
|
|
|
|
x = desktop.x() + ( desktop.width() - windowSize.width() ) / 2;
|
|
|
|
|
|
|
|
/// Try the to-the-bottom placement
|
|
|
|
if ( currentPos.y() + 15 + windowSize.height() <= desktop.bottomLeft().y() )
|
|
|
|
y = currentPos.y() + 15;
|
|
|
|
else
|
|
|
|
/// Try the to-the-top placement
|
|
|
|
if ( currentPos.y() - 15 - windowSize.height() >= desktop.y() )
|
|
|
|
y = currentPos.y() - 15 - windowSize.height();
|
|
|
|
else
|
|
|
|
// Center it
|
|
|
|
y = desktop.y() + ( desktop.height() - windowSize.height() ) / 2;
|
|
|
|
|
|
|
|
move( x, y );
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
|
|
|
|
show();
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
if ( giveFocus )
|
|
|
|
{
|
|
|
|
activateWindow();
|
|
|
|
raise();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !ui.pinButton->isChecked() )
|
|
|
|
{
|
|
|
|
mouseEnteredOnce = false;
|
|
|
|
// Need to monitor the mouse so we know when to hide the window
|
|
|
|
interceptMouse();
|
|
|
|
}
|
|
|
|
|
2009-02-08 16:35:30 +00:00
|
|
|
// This produced some funky mouse grip-related bugs so we commented it out
|
|
|
|
//QApplication::processEvents(); // Make window appear immediately no matter what
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
2009-12-27 12:00:59 +00:00
|
|
|
else
|
|
|
|
if ( ui.pinButton->isChecked() )
|
|
|
|
{
|
|
|
|
// Pinned-down window isn't always on top, so we need to raise it
|
|
|
|
show();
|
|
|
|
activateWindow();
|
|
|
|
raise();
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
|
|
|
|
initiateTranslation();
|
|
|
|
}
|
|
|
|
|
2009-02-05 20:55:00 +00:00
|
|
|
QString ScanPopup::elideInputWord()
|
|
|
|
{
|
|
|
|
return inputWord.size() > 32 ? inputWord.mid( 0, 32 ) + "..." : inputWord;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-10 12:48:40 +00:00
|
|
|
void ScanPopup::currentGroupChanged( QString const & )
|
2009-02-01 00:08:08 +00:00
|
|
|
{
|
2010-03-30 20:15:55 +00:00
|
|
|
updateDictionaryBar();
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
if ( isVisible() )
|
|
|
|
initiateTranslation();
|
2009-02-06 17:04:11 +00:00
|
|
|
|
2009-04-10 12:48:40 +00:00
|
|
|
cfg.lastPopupGroupId = ui.groupList->getCurrentGroup();
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::initiateTranslation()
|
|
|
|
{
|
2009-04-11 16:44:14 +00:00
|
|
|
ui.wordListButton->hide();
|
|
|
|
ui.pronounceButton->hide();
|
|
|
|
|
2009-04-10 12:48:40 +00:00
|
|
|
definition->showDefinition( inputWord, ui.groupList->getCurrentGroup() );
|
2009-03-26 19:00:08 +00:00
|
|
|
wordFinder.prefixMatch( inputWord, getActiveDicts() );
|
2009-10-21 19:37:07 +00:00
|
|
|
|
|
|
|
history.addItem( History::Item( ui.groupList->getCurrentGroup(),
|
|
|
|
inputWord.trimmed() ) );
|
2012-02-16 14:56:25 +00:00
|
|
|
// history.save();
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vector< sptr< Dictionary::Class > > const & ScanPopup::getActiveDicts()
|
|
|
|
{
|
2010-04-30 09:56:40 +00:00
|
|
|
int current = ui.groupList->currentIndex();
|
2009-02-01 00:08:08 +00:00
|
|
|
|
2010-04-30 09:56:40 +00:00
|
|
|
if ( current < 0 || current >= (int) groups.size() )
|
|
|
|
{
|
|
|
|
// This shouldn't ever happen
|
|
|
|
return allDictionaries;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !dictionaryBar.toggleViewAction()->isChecked() )
|
|
|
|
return groups[ current ].dictionaries;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vector< sptr< Dictionary::Class > > const & activeDicts =
|
|
|
|
groups[ current ].dictionaries;
|
|
|
|
|
|
|
|
// Populate the special dictionariesUnmuted array with only unmuted
|
|
|
|
// dictionaries
|
|
|
|
|
|
|
|
dictionariesUnmuted.clear();
|
|
|
|
dictionariesUnmuted.reserve( activeDicts.size() );
|
|
|
|
|
|
|
|
for( unsigned x = 0; x < activeDicts.size(); ++x )
|
|
|
|
if ( !cfg.popupMutedDictionaries.contains(
|
|
|
|
QString::fromStdString( activeDicts[ x ]->getId() ) ) )
|
|
|
|
dictionariesUnmuted.push_back( activeDicts[ x ] );
|
|
|
|
|
|
|
|
return dictionariesUnmuted;
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
bool ScanPopup::eventFilter( QObject * watched, QEvent * event )
|
|
|
|
{
|
|
|
|
if ( mouseIntercepted )
|
|
|
|
{
|
|
|
|
// We're only interested in our events
|
|
|
|
|
|
|
|
if ( event->type() == QEvent::MouseMove )
|
|
|
|
{
|
2011-06-19 18:50:11 +00:00
|
|
|
// DPRINTF( "Object: %s\n", watched->objectName().toUtf8().data() );
|
2010-01-02 23:26:09 +00:00
|
|
|
QMouseEvent * mouseEvent = ( QMouseEvent * ) event;
|
2010-07-03 16:24:30 +00:00
|
|
|
reactOnMouseMove( mouseEvent->globalPos() );
|
|
|
|
}
|
|
|
|
}
|
2010-01-02 23:26:09 +00:00
|
|
|
|
2010-07-03 16:24:30 +00:00
|
|
|
return QMainWindow::eventFilter( watched, event );
|
|
|
|
}
|
2010-01-02 23:26:09 +00:00
|
|
|
|
2010-07-03 16:24:30 +00:00
|
|
|
void ScanPopup::reactOnMouseMove( QPoint const & p )
|
|
|
|
{
|
|
|
|
if ( geometry().contains( p ) )
|
|
|
|
{
|
2011-06-19 18:50:11 +00:00
|
|
|
// DPRINTF( "got inside\n" );
|
2010-01-02 23:26:09 +00:00
|
|
|
|
2010-07-03 16:24:30 +00:00
|
|
|
hideTimer.stop();
|
|
|
|
mouseEnteredOnce = true;
|
|
|
|
uninterceptMouse();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-19 18:50:11 +00:00
|
|
|
// DPRINTF( "outside\n" );
|
2010-07-03 16:24:30 +00:00
|
|
|
// We're in grab mode and outside the window - calculate the
|
|
|
|
// distance from it. We might want to hide it.
|
|
|
|
|
|
|
|
// When the mouse has entered once, we don't allow it stayng outside,
|
|
|
|
// but we give a grace period for it to return.
|
|
|
|
int proximity = mouseEnteredOnce ? 0 : 60;
|
|
|
|
|
|
|
|
// Note: watched == this ensures no other child objects popping out are
|
|
|
|
// receiving this event, meaning there's basically nothing under the
|
|
|
|
// cursor.
|
|
|
|
if ( /*watched == this &&*/
|
|
|
|
!frameGeometry().adjusted( -proximity, -proximity, proximity, proximity ).
|
|
|
|
contains( p ) )
|
|
|
|
{
|
|
|
|
// We've way too far from the window -- hide the popup
|
|
|
|
|
|
|
|
// If the mouse never entered the popup, hide the window instantly --
|
|
|
|
// the user just moved the cursor further away from the window.
|
|
|
|
|
|
|
|
if ( !mouseEnteredOnce )
|
|
|
|
hideWindow();
|
|
|
|
else
|
|
|
|
hideTimer.start();
|
2010-01-02 23:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-06 18:43:07 +00:00
|
|
|
void ScanPopup::mousePressEvent( QMouseEvent * ev )
|
|
|
|
{
|
2010-01-02 23:26:09 +00:00
|
|
|
// With mouse grabs, the press can occur anywhere on the screen, which
|
|
|
|
// might mean hiding the window.
|
|
|
|
|
|
|
|
if ( !frameGeometry().contains( ev->globalPos() ) )
|
|
|
|
{
|
|
|
|
hideWindow();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
if ( ev->button() == Qt::LeftButton )
|
|
|
|
{
|
|
|
|
startPos = ev->globalPos();
|
|
|
|
setCursor( Qt::ClosedHandCursor );
|
|
|
|
}
|
2009-02-06 18:43:07 +00:00
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::mousePressEvent( ev );
|
2009-02-06 18:43:07 +00:00
|
|
|
}
|
|
|
|
|
2009-02-06 13:05:25 +00:00
|
|
|
void ScanPopup::mouseMoveEvent( QMouseEvent * event )
|
|
|
|
{
|
2010-01-02 23:26:09 +00:00
|
|
|
if ( event->buttons() && cursor().shape() == Qt::ClosedHandCursor )
|
2009-02-06 18:43:07 +00:00
|
|
|
{
|
|
|
|
QPoint newPos = event->globalPos();
|
|
|
|
|
|
|
|
QPoint delta = newPos - startPos;
|
|
|
|
|
|
|
|
startPos = newPos;
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
// Move the window
|
2009-02-06 18:43:07 +00:00
|
|
|
|
|
|
|
move( pos() + delta );
|
|
|
|
}
|
2009-12-27 12:00:59 +00:00
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::mouseMoveEvent( event );
|
2009-02-06 13:05:25 +00:00
|
|
|
}
|
|
|
|
|
2009-02-06 18:43:07 +00:00
|
|
|
void ScanPopup::mouseReleaseEvent( QMouseEvent * ev )
|
|
|
|
{
|
|
|
|
unsetCursor();
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::mouseReleaseEvent( ev );
|
2009-02-06 18:43:07 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
void ScanPopup::leaveEvent( QEvent * event )
|
|
|
|
{
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::leaveEvent( event );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
// We hide the popup when the mouse leaves it.
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
// Combo-boxes seem to generate leave events for their parents when
|
|
|
|
// unfolded, so we check coordinates as well.
|
2009-02-06 18:43:07 +00:00
|
|
|
// If the dialog is pinned, we don't hide the popup.
|
|
|
|
// If some mouse buttons are pressed, we don't hide the popup either,
|
|
|
|
// since it indicates the move operation is underway.
|
|
|
|
if ( !ui.pinButton->isChecked() && !geometry().contains( QCursor::pos() ) &&
|
|
|
|
QApplication::mouseButtons() == Qt::NoButton )
|
|
|
|
{
|
2009-04-10 13:56:38 +00:00
|
|
|
hideTimer.start();
|
2009-02-06 18:43:07 +00:00
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
|
2009-04-10 13:56:38 +00:00
|
|
|
void ScanPopup::enterEvent( QEvent * event )
|
|
|
|
{
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::enterEvent( event );
|
2009-04-10 13:56:38 +00:00
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
if ( mouseEnteredOnce )
|
|
|
|
{
|
|
|
|
// We "enter" first time via our event filter. This seems to evade some
|
|
|
|
// unexpected behavior under Windows.
|
|
|
|
|
|
|
|
// If there was a countdown to hide the window, stop it.
|
|
|
|
hideTimer.stop();
|
|
|
|
}
|
2009-04-10 13:56:38 +00:00
|
|
|
}
|
|
|
|
|
2009-02-08 21:26:35 +00:00
|
|
|
void ScanPopup::showEvent( QShowEvent * ev )
|
|
|
|
{
|
2010-03-30 20:15:55 +00:00
|
|
|
QMainWindow::showEvent( ev );
|
2009-02-08 21:26:35 +00:00
|
|
|
|
2009-05-18 18:01:50 +00:00
|
|
|
if ( groups.size() <= 1 ) // Only the default group? Hide then.
|
2009-02-08 21:26:35 +00:00
|
|
|
ui.groupList->hide();
|
2010-03-30 20:15:55 +00:00
|
|
|
|
|
|
|
if ( ui.showDictionaryBar->isChecked() != dictionaryBar.isVisible() )
|
|
|
|
{
|
|
|
|
ui.showDictionaryBar->setChecked( dictionaryBar.isVisible() );
|
|
|
|
updateDictionaryBar();
|
|
|
|
}
|
2009-02-08 21:26:35 +00:00
|
|
|
}
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
void ScanPopup::prefixMatchFinished()
|
2009-02-01 00:08:08 +00:00
|
|
|
{
|
2009-03-26 19:00:08 +00:00
|
|
|
// Check that there's a window there at all
|
|
|
|
if ( isVisible() )
|
2009-02-01 00:08:08 +00:00
|
|
|
{
|
2009-03-26 19:00:08 +00:00
|
|
|
if ( wordFinder.getErrorString().size() )
|
|
|
|
{
|
|
|
|
ui.queryError->setToolTip( wordFinder.getErrorString() );
|
|
|
|
ui.queryError->show();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ui.queryError->hide();
|
|
|
|
|
2009-04-17 13:51:50 +00:00
|
|
|
ui.wordListButton->setVisible( wordFinder.getResults().size() );
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-10 15:52:08 +00:00
|
|
|
void ScanPopup::on_wordListButton_clicked()
|
2009-02-01 00:08:08 +00:00
|
|
|
{
|
|
|
|
if ( !isVisible() )
|
|
|
|
return;
|
|
|
|
|
2009-04-17 13:51:50 +00:00
|
|
|
WordFinder::SearchResults const & results = wordFinder.getResults();
|
2009-04-10 15:52:08 +00:00
|
|
|
|
|
|
|
if ( results.empty() )
|
2009-02-01 00:08:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
QMenu menu( this );
|
|
|
|
|
2009-12-27 12:00:59 +00:00
|
|
|
unsigned total = results.size() < 40 ? results.size() : 40;
|
2009-04-10 15:52:08 +00:00
|
|
|
|
|
|
|
for( unsigned x = 0; x < total; ++x )
|
|
|
|
{
|
|
|
|
// Some items are just too large! For now skip them.
|
|
|
|
|
|
|
|
if ( results[ x ].first.size() > 64 )
|
|
|
|
{
|
|
|
|
if ( total < results.size() )
|
|
|
|
++total;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
menu.addAction( results[ x ].first );
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
|
2009-04-10 15:52:08 +00:00
|
|
|
QAction * result = menu.exec( mapToGlobal( ui.wordListButton->pos() ) +
|
|
|
|
QPoint( 0, ui.wordListButton->height() ) );
|
2009-02-01 00:08:08 +00:00
|
|
|
|
|
|
|
if ( result )
|
2009-04-10 12:48:40 +00:00
|
|
|
definition->showDefinition( result->text(), ui.groupList->getCurrentGroup() );
|
2009-02-01 00:08:08 +00:00
|
|
|
}
|
|
|
|
|
2009-04-10 21:07:03 +00:00
|
|
|
void ScanPopup::on_pronounceButton_clicked()
|
|
|
|
{
|
|
|
|
definition->playSound();
|
|
|
|
}
|
|
|
|
|
2009-02-01 00:08:08 +00:00
|
|
|
void ScanPopup::pinButtonClicked( bool checked )
|
|
|
|
{
|
|
|
|
if ( checked )
|
2009-02-05 20:55:00 +00:00
|
|
|
{
|
2010-01-02 23:26:09 +00:00
|
|
|
uninterceptMouse();
|
|
|
|
|
2009-02-05 20:55:00 +00:00
|
|
|
setWindowFlags( Qt::Dialog );
|
|
|
|
setWindowTitle( elideInputWord() );
|
2010-03-30 20:15:55 +00:00
|
|
|
dictionaryBar.setMovable( true );
|
2009-04-10 13:56:38 +00:00
|
|
|
hideTimer.stop();
|
2009-02-05 20:55:00 +00:00
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
else
|
2010-01-02 23:26:09 +00:00
|
|
|
{
|
2010-03-30 20:15:55 +00:00
|
|
|
dictionaryBar.setMovable( false );
|
2010-01-02 23:26:09 +00:00
|
|
|
setWindowFlags( popupWindowFlags );
|
|
|
|
|
|
|
|
mouseEnteredOnce = true;
|
|
|
|
}
|
2009-02-01 00:08:08 +00:00
|
|
|
|
|
|
|
show();
|
|
|
|
}
|
2009-04-10 13:56:38 +00:00
|
|
|
|
2010-03-30 20:15:55 +00:00
|
|
|
void ScanPopup::on_showDictionaryBar_clicked( bool checked )
|
|
|
|
{
|
|
|
|
dictionaryBar.setVisible( checked );
|
|
|
|
updateDictionaryBar();
|
|
|
|
definition->updateMutedContents();
|
|
|
|
}
|
|
|
|
|
2009-04-10 13:56:38 +00:00
|
|
|
void ScanPopup::hideTimerExpired()
|
|
|
|
{
|
|
|
|
if ( isVisible() )
|
2010-01-02 23:26:09 +00:00
|
|
|
hideWindow();
|
2009-04-10 13:56:38 +00:00
|
|
|
}
|
2009-04-10 21:07:03 +00:00
|
|
|
|
2009-04-11 16:44:14 +00:00
|
|
|
void ScanPopup::altModeExpired()
|
|
|
|
{
|
|
|
|
// The alt mode duration has expired, so there's no need to poll for modifiers
|
|
|
|
// anymore.
|
|
|
|
altModePollingTimer.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::altModePoll()
|
|
|
|
{
|
|
|
|
if ( !pendingInputWord.size() )
|
|
|
|
{
|
|
|
|
altModePollingTimer.stop();
|
|
|
|
altModeExpirationTimer.stop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ( checkModifiersPressed( cfg.preferences.scanPopupModifiers ) )
|
|
|
|
{
|
|
|
|
altModePollingTimer.stop();
|
|
|
|
altModeExpirationTimer.stop();
|
|
|
|
|
|
|
|
inputWord = pendingInputWord;
|
|
|
|
engagePopup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:42:04 +00:00
|
|
|
void ScanPopup::pageLoaded( ArticleView * )
|
2009-04-10 21:07:03 +00:00
|
|
|
{
|
|
|
|
ui.pronounceButton->setVisible( definition->hasSound() );
|
|
|
|
|
|
|
|
if ( cfg.preferences.pronounceOnLoadPopup )
|
|
|
|
definition->playSound();
|
|
|
|
}
|
2009-05-16 11:14:43 +00:00
|
|
|
|
2011-07-14 20:11:57 +00:00
|
|
|
void ScanPopup::showStatusBarMessage( QString const & message, int timeout, QPixmap const & icon )
|
2011-07-14 08:17:59 +00:00
|
|
|
{
|
2011-07-14 20:11:57 +00:00
|
|
|
mainStatusBar->showMessage( message, timeout, icon );
|
2011-07-14 08:17:59 +00:00
|
|
|
}
|
|
|
|
|
2009-05-16 11:14:43 +00:00
|
|
|
void ScanPopup::escapePressed()
|
|
|
|
{
|
|
|
|
if ( !definition->closeSearch() )
|
2010-01-02 23:26:09 +00:00
|
|
|
hideWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::hideWindow()
|
|
|
|
{
|
|
|
|
uninterceptMouse();
|
|
|
|
|
|
|
|
hideTimer.stop();
|
|
|
|
unsetCursor();
|
|
|
|
hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::interceptMouse()
|
|
|
|
{
|
|
|
|
if ( !mouseIntercepted )
|
2009-05-16 11:14:43 +00:00
|
|
|
{
|
2010-07-03 16:24:30 +00:00
|
|
|
// We used to grab the mouse -- but this doesn't always work reliably
|
|
|
|
// (e.g. doesn't work at all in Windows 7 for some reason). Therefore
|
|
|
|
// we use a polling timer now.
|
|
|
|
|
|
|
|
// grabMouse();
|
|
|
|
mouseGrabPollTimer.start();
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
qApp->installEventFilter( this );
|
|
|
|
|
|
|
|
mouseIntercepted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-03 16:24:30 +00:00
|
|
|
void ScanPopup::mouseGrabPoll()
|
|
|
|
{
|
|
|
|
if ( mouseIntercepted )
|
|
|
|
reactOnMouseMove( QCursor::pos() );
|
|
|
|
}
|
|
|
|
|
2010-01-02 23:26:09 +00:00
|
|
|
void ScanPopup::uninterceptMouse()
|
|
|
|
{
|
|
|
|
if ( mouseIntercepted )
|
|
|
|
{
|
|
|
|
qApp->removeEventFilter( this );
|
2010-07-03 16:24:30 +00:00
|
|
|
mouseGrabPollTimer.stop();
|
|
|
|
// releaseMouse();
|
2010-01-02 23:26:09 +00:00
|
|
|
|
|
|
|
mouseIntercepted = false;
|
2009-05-16 11:14:43 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-30 20:15:55 +00:00
|
|
|
|
|
|
|
void ScanPopup::updateDictionaryBar()
|
|
|
|
{
|
|
|
|
if ( !dictionaryBar.toggleViewAction()->isChecked() )
|
|
|
|
return; // It's not enabled, therefore hidden -- don't waste time
|
|
|
|
|
2010-04-30 09:56:40 +00:00
|
|
|
Instances::Group const * grp =
|
|
|
|
groups.findGroup( ui.groupList->getCurrentGroup() );
|
|
|
|
|
|
|
|
if ( grp ) // Should always be !0, but check as a safeguard
|
|
|
|
dictionaryBar.setDictionaries( grp->dictionaries );
|
2010-03-30 20:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScanPopup::mutedDictionariesChanged()
|
|
|
|
{
|
|
|
|
if ( dictionaryBar.toggleViewAction()->isChecked() )
|
|
|
|
definition->updateMutedContents();
|
|
|
|
}
|
2011-11-16 12:52:25 +00:00
|
|
|
|
|
|
|
void ScanPopup::on_sendWordButton_clicked()
|
|
|
|
{
|
|
|
|
if ( !isVisible() )
|
|
|
|
return;
|
|
|
|
if( !ui.pinButton->isChecked() )
|
|
|
|
{
|
|
|
|
definition->closeSearch();
|
|
|
|
hideWindow();
|
|
|
|
}
|
|
|
|
emit sendWordToMainWindow( definition->getTitle() );
|
|
|
|
}
|