Win-specific: Scan popup now work in GoldenDict article tabs

This commit is contained in:
Abs62 2012-09-19 03:01:31 +04:00
parent 3abb74ad51
commit 3de1e09663
4 changed files with 230 additions and 0 deletions

View file

@ -21,7 +21,11 @@
#ifdef Q_OS_WIN32
#include <windows.h>
#include <mmsystem.h> // For PlaySound
#include <QWebElement>
#include <QPainter>
#endif
#include <QBuffer>
// Phonon headers are a mess. How to include them properly? Send patches if you
@ -1568,3 +1572,173 @@ void ArticleView::switchExpandOptionalParts()
emit setExpandMode( expandOptionalParts );
reload();
}
#ifdef Q_OS_WIN32
void ArticleView::readTag( const QString & from, QString & to, int & count )
{
QChar ch, prev_ch;
bool inQuote = false, inDoublequote = false;
to.append( ch = prev_ch = from[ count++ ] );
while( count < from.size() )
{
ch = from[ count ];
if( ch == '>' && !( inQuote || inDoublequote ) )
{
to.append( ch );
break;
}
if( ch == '\'' )
inQuote = !inQuote;
if( ch == '\"' )
inDoublequote = !inDoublequote;
to.append( prev_ch = ch );
count++;
}
}
QString ArticleView::insertSpans( QString const & html )
{
QChar ch;
QString newContent;
bool inSpan = false, escaped = false;
/// Enclose every word in string (exclude tags) with <span></span>
for( int i = 0; i < html.size(); i++ )
{
ch = html[ i ];
if( ch == '&' )
{
escaped = true;
if( inSpan )
{
newContent.append( "</span>" );
inSpan = false;
}
newContent.append( ch );
continue;
}
if( ch == '<' ) // Skip tag
{
escaped = false;
if( inSpan )
{
newContent.append( "</span>" );
inSpan = false;
}
readTag( html, newContent, i );
continue;
}
if( escaped )
{
if( ch == ';' )
escaped = false;
newContent.append( ch );
continue;
}
if( !inSpan && ( ch.isLetterOrNumber() || ch.isLowSurrogate() ) )
{
newContent.append( "<span>");
inSpan = true;
}
if( inSpan && !( ch.isLetterOrNumber() || ch.isLowSurrogate() ) )
{
newContent.append( "</span>");
inSpan = false;
}
if( ch.isLowSurrogate() )
{
newContent.append( ch );
ch = html[ ++i ];
}
newContent.append( ch );
}
if( inSpan )
newContent.append( "</span>" );
return newContent;
}
QString ArticleView::checkElement( QWebElement & elem, QPoint const & pt )
{
/// Search for lower-level matching element
QWebElement parentElem = elem;
QWebElement childElem = elem.firstChild();
while( !childElem.isNull() )
{
if( childElem.geometry().contains( pt ) )
{
parentElem = childElem;
childElem = parentElem.firstChild();
continue;
}
childElem = childElem.nextSibling();
}
return parentElem.toPlainText();
}
QString ArticleView::wordAtPoint( int x, int y )
{
QString word;
if( popupView )
return word;
QPoint pos = mapFromGlobal( QPoint( x, y ) );
QWebFrame *frame = ui.definition->page()->frameAt( pos );
if( !frame )
return word;
QPoint posWithScroll = pos + frame->scrollPosition();
/// Find target HTML element
QWebHitTestResult result = frame->hitTestContent( pos );
QWebElement baseElem = result.enclosingBlockElement();
if( baseElem.tagName().compare( "BODY" ) == 0 || /// Assume empty field position
baseElem.tagName().compare( "HTML" ) == 0 ||
baseElem.tagName().compare( "HEAD" ) == 0 )
return word;
/// Enclose every word be <span> </span>
QString content = baseElem.toInnerXml();
QString newContent = insertSpans( content );
/// Set new code and re-render it to fill geometry
QImage img( baseElem.geometry().width(), baseElem.geometry().height(), QImage::Format_Mono );
img.fill( 0 );
QPainter painter( & img );
baseElem.setInnerXml( newContent );
baseElem.render( &painter );
/// Search in all child elements and check it
QWebElementCollection elemCollection = baseElem.findAll( "*" );
foreach ( QWebElement elem, elemCollection )
{
if( elem.geometry().contains( posWithScroll ) )
word = checkElement( elem, posWithScroll );
if( !word.isEmpty() )
break;
}
/// Restore old content
baseElem.setInnerXml( content );
return word;
}
#endif

View file

@ -298,6 +298,19 @@ protected:
// We need this to hide the search bar when we're showed
void showEvent( QShowEvent * );
#ifdef Q_OS_WIN32
/// Search inside web page for word under cursor
private:
QString insertSpans( QString const & html );
void readTag( QString const & from, QString & to, int & count );
QString checkElement( QWebElement & elem, const QPoint & pt );
public:
QString wordAtPoint( int x, int y );
#endif
};
#endif

View file

@ -25,6 +25,11 @@
#include "lionsupport.h"
#endif
#ifdef Q_OS_WIN32
#include <windows.h>
#include "mouseover_win32/GDDataTranfer.h"
#endif
using std::set;
using std::wstring;
using std::map;
@ -527,6 +532,9 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
#ifdef Q_OS_MAC
LionSupport::addFullscreen(this);
#endif
#ifdef Q_OS_WIN32
gdAskMessage = RegisterWindowMessage( GD_MESSAGE_NAME );
#endif
}
void MainWindow::ctrlTabPressed()
@ -1021,6 +1029,9 @@ ArticleView * MainWindow::createNewTab( bool switchToIt,
view->setZoomFactor( cfg.preferences.zoomFactor );
#ifdef Q_OS_WIN32
view->installEventFilter( this );
#endif
return view;
}
@ -2950,3 +2961,28 @@ void MainWindow::switchExpandOptionalPartsMode()
if( view )
view->switchExpandOptionalParts();
}
#ifdef Q_OS_WIN32
bool MainWindow::winEvent( MSG * message, long * result )
{
if( message->message != gdAskMessage )
return false;
*result = 0;
ArticleView * view = getCurrentArticleView();
if( !view )
return true;
LPGDDataStruct lpdata = ( LPGDDataStruct ) message->lParam;
QString str = view->wordAtPoint( lpdata->Pt.x, lpdata->Pt.y );
str.truncate( lpdata->dwMaxLength - 1 );
memset( lpdata->cwData, 0, lpdata->dwMaxLength * sizeof( WCHAR ) );
str.toWCharArray( lpdata->cwData );
*result = 1;
return true;
}
#endif

View file

@ -341,6 +341,13 @@ private slots:
signals:
/// Set optional parts expand mode for all tabs
void setExpandOptionalParts( bool expand );
#ifdef Q_OS_WIN32
/// For receiving message from scan libraries
protected:
unsigned gdAskMessage;
bool winEvent( MSG * message, long * result );
#endif
};
#endif