Scan popup functionality implemented, among with other small improvements.

For now, the modifier key is hardcoded to be Ctrl.
This commit is contained in:
Konstantin Isakov 2009-02-01 00:08:08 +00:00
parent 2e8cb955c8
commit 2be1c2b375
25 changed files with 763 additions and 201 deletions

View file

@ -22,13 +22,9 @@ ArticleMaker::ArticleMaker( vector< sptr< Dictionary::Class > > const & dictiona
{
}
string ArticleMaker::makeDefinitionFor( QString const & inWord,
QString const & group ) const
std::string ArticleMaker::makeHtmlHeader( QString const & word,
QString const & icon )
{
printf( "group = %ls\n", group.toStdWString().c_str() );
wstring word = inWord.trimmed().toStdWString();
string result =
"<html><head>"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">";
@ -42,7 +38,24 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
result += "</style>\n";
}
result += "<title>" + Html::escape( Utf8::encode( word ) ) + "</title>";
result += "<title>" + Html::escape( Utf8::encode( word.toStdWString() ) ) + "</title>";
// This doesn't seem to be much of influence right now, but we'll keep
// it anyway.
if ( icon.size() )
result += "<link rel=\"icon\" type=\"image/png\" href=\"qrcx://localhost/flags/" + Html::escape( icon.toUtf8().data() ) + "\" />\n";
result += "</head><body>";
return result;
}
string ArticleMaker::makeDefinitionFor( QString const & inWord,
QString const & group ) const
{
printf( "group = %ls\n", group.toStdWString().c_str() );
wstring word = inWord.trimmed().toStdWString();
// Find the given group
@ -60,14 +73,9 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
std::vector< sptr< Dictionary::Class > > const & activeDicts =
activeGroup ? activeGroup->dictionaries : dictionaries;
if ( activeGroup && activeGroup->icon.size() )
{
// This doesn't seem to be much of influence right now, but we'll keep
// it anyway.
result += "<link rel=\"icon\" type=\"image/png\" href=\"qrcx://localhost/flags/" + Html::escape( activeGroup->icon.toUtf8().data() ) + "\" />\n";
}
result += "</head><body>";
string result = makeHtmlHeader( inWord.trimmed(),
activeGroup && activeGroup->icon.size() ?
activeGroup->icon : QString() );
DictLock _;
@ -101,7 +109,9 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
printf( "From %s: %s\n", activeDicts[ x ]->getName().c_str(), body.c_str() );
result += "<div class=\"gddictname\">From " + Html::escape( activeDicts[ x ]->getName() ) + "</div>" + body;
result += string( "<div class=\"gddictname\">" ) +
tr( "From " ).toUtf8().data() +
Html::escape( activeDicts[ x ]->getName() ) + "</div>" + body;
}
catch( Dictionary::exNoSuchWord & )
{
@ -114,6 +124,15 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
return result;
}
string ArticleMaker::makeNotFoundTextFor( QString const & word,
QString const & group ) const
{
return makeHtmlHeader( word, QString() ) +
"<div class=\"gdnotfound\"><p>" +
tr( "No translation for <b>%1</b> was found in group <b>%2</b>." ).
arg( QString::fromUtf8( Html::escape( word.toUtf8().data() ).c_str() ) ).
arg( QString::fromUtf8(Html::escape( group.toUtf8().data() ).c_str() ) ).
toUtf8().data()
+"</p></div>"
"</body></html>";
}

View file

@ -4,12 +4,15 @@
#ifndef __ARTICLE_MAKER_HH_INCLUDED__
#define __ARTICLE_MAKER_HH_INCLUDED__
#include <QObject>
#include "dictionary.hh"
#include "instances.hh"
/// This class generates the article's body for the given lookup request
class ArticleMaker
class ArticleMaker: public QObject
{
Q_OBJECT // We make it QObject to use tr() conveniently
std::vector< sptr< Dictionary::Class > > const & dictionaries;
std::vector< Instances::Group > const & groups;
@ -25,6 +28,16 @@ public:
/// Looks up the given word within the given group, and creates a full html
/// page text containing its definition.
std::string makeDefinitionFor( QString const & word, QString const & group ) const;
/// Makes up a text which states that no translation for the given word
/// was found. Sometimes it's better to call this directly when it's already
/// known that there's no translation.
std::string makeNotFoundTextFor( QString const & word, QString const & group ) const;
private:
/// Makes everything up to and including the opening body tag.
static std::string makeHtmlHeader( QString const & word, QString const & icon );
};
#endif

View file

@ -47,8 +47,12 @@ bool ArticleNetworkAccessManager::getResource( QUrl const & url,
if ( url.scheme() == "gdlookup" )
{
string result = articleMaker.makeDefinitionFor( url.queryItemValue( "word" ),
url.queryItemValue( "group" ) );
QString word = url.queryItemValue( "word" );
QString group = url.queryItemValue( "group" );
string result = ( url.queryItemValue( "notfound" ) != "1" ) ?
articleMaker.makeDefinitionFor( word, group ) :
articleMaker.makeNotFoundTextFor( word, group );
data.resize( result.size() );

View file

@ -6,6 +6,7 @@
#include <QMessageBox>
#include <QWebHitTestResult>
#include <QMenu>
#include <QDesktopServices>
ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm,
@ -48,6 +49,19 @@ void ArticleView::showDefinition( QString const & word, QString const & group )
ui.definition->load( req );
}
void ArticleView::showNotFound( QString const & word, QString const & group )
{
QUrl req;
req.setScheme( "gdlookup" );
req.setHost( "localhost" );
req.addQueryItem( "word", word );
req.addQueryItem( "group", group );
req.addQueryItem( "notfound", "1" );
ui.definition->load( req );
}
void ArticleView::handleTitleChanged( QString const & title )
{
emit titleChanged( this, title );
@ -162,6 +176,13 @@ void ArticleView::linkClicked( QUrl const & url )
printf( "%s\n", e.what() );
}
}
else
if ( url.scheme() == "http" || url.scheme() == "https" ||
url.scheme() == "ftp" || url.scheme() == "mailto" )
{
// Use the system handler for the conventional internet links
QDesktopServices::openUrl( url );
}
}
void ArticleView::contextMenuRequested( QPoint const & pos )

View file

@ -34,6 +34,9 @@ public:
/// Shows the definition of the given word with the given group
void showDefinition( QString const & word, QString const & group );
/// Shows the page stating that the given word could not be found.
void showNotFound( QString const & word, QString const & group );
/// Goes back in history
void back()
{ ui.definition->back(); }

View file

@ -200,4 +200,9 @@ QString getUserCssFileName() throw( exError )
return getHomeDir().filePath( "style.css" );
}
QString getUserQtCssFileName() throw( exError )
{
return getHomeDir().filePath( "qt-style.css" );
}
}

View file

@ -51,6 +51,9 @@ QString getIndexDir() throw( exError );
/// Returns the user .css file name.
QString getUserCssFileName() throw( exError );
/// Returns the user .css file name for the Qt interface customization.
QString getUserQtCssFileName() throw( exError );
}
#endif

View file

@ -55,7 +55,10 @@ HEADERS += folding.hh \
articleview.hh \
externalviewer.hh \
dictlock.hh \
wordfinder.hh
wordfinder.hh \
groupcombobox.hh \
griparea.hh \
keyboardstate.hh
FORMS += groups.ui dictgroupwidget.ui mainwindow.ui sources.ui initializing.ui\
@ -67,6 +70,7 @@ SOURCES += folding.cc main.cc dictionary.cc md5.c config.cc sources.cc \
chunkedstorage.cc xdxf2html.cc iconv.cc lsa.cc htmlescape.cc \
dsl.cc dsl_details.cc filetype.cc fsencoding.cc groups.cc \
groups_widgets.cc instances.cc article_maker.cc scanpopup.cc \
articleview.cc externalviewer.cc dictlock.cc wordfinder.cc
articleview.cc externalviewer.cc dictlock.cc wordfinder.cc \
groupcombobox.cc griparea.cc keyboardstate.cc
RESOURCES += resources.qrc flags.qrc

53
src/griparea.cc Normal file
View file

@ -0,0 +1,53 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "griparea.hh"
#include <QMouseEvent>
GripArea::GripArea( QWidget * parent ): QWidget( parent )
{
setCursor( Qt::OpenHandCursor );
}
void GripArea::paintEvent( QPaintEvent * )
{
if ( isEnabled() )
{
QStylePainter p( this );
QStyleOptionDockWidgetV2 opt;
opt.initFrom( this );
p.drawControl( QStyle::CE_DockWidgetTitle, opt );
}
}
void GripArea::mousePressEvent( QMouseEvent * ev )
{
startPos = ev->globalPos();
setCursor( Qt::ClosedHandCursor );
}
void GripArea::mouseMoveEvent( QMouseEvent * ev )
{
QPoint newPos = ev->globalPos();
QPoint delta = newPos - startPos;
startPos = newPos;
// Find a top-level window
QWidget * w = this;
while( w && !w->isWindow() && w->windowType() != Qt::SubWindow )
w = w->parentWidget();
w->move( w->pos() + delta );
}
void GripArea::mouseReleaseEvent( QMouseEvent * )
{
setCursor( Qt::OpenHandCursor );
}

32
src/griparea.hh Normal file
View file

@ -0,0 +1,32 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#ifndef __GRIPAREA_HH_INCLUDED__
#define __GRIPAREA_HH_INCLUDED__
#include <QWidget>
#include <QStylePainter>
#include <QStyleOptionDockWidget>
/// A grip area to move a window, looking like a dock widget's title area.
class GripArea: public QWidget
{
Q_OBJECT
public:
GripArea( QWidget * parent );
protected:
virtual void paintEvent( QPaintEvent * );
virtual void mousePressEvent( QMouseEvent * );
virtual void mouseMoveEvent( QMouseEvent * );
virtual void mouseReleaseEvent( QMouseEvent * );
private:
QPoint startPos;
};
#endif

28
src/groupcombobox.cc Normal file
View file

@ -0,0 +1,28 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "groupcombobox.hh"
GroupComboBox::GroupComboBox( QWidget * parent ): QComboBox( parent )
{
setSizeAdjustPolicy( AdjustToContents );
}
void GroupComboBox::fill( Instances::Groups const & groups )
{
QString prev = currentText();
clear();
for( unsigned x = 0; x < groups.size(); ++x )
{
QIcon icon = groups[ x ].icon.size() ?
QIcon( ":/flags/" + groups[ x ].icon ) : QIcon();
addItem( icon, groups[ x ].name );
if ( prev == groups[ x ].name )
setCurrentIndex( x );
}
}

24
src/groupcombobox.hh Normal file
View file

@ -0,0 +1,24 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#ifndef __GROUPCOMBOBOX_HH_INCLUDED__
#define __GROUPCOMBOBOX_HH_INCLUDED__
#include <QComboBox>
#include "instances.hh"
/// This is a combo box which is for choosing the dictionary group
class GroupComboBox: public QComboBox
{
Q_OBJECT
public:
GroupComboBox( QWidget * parent );
/// Fills combo-box with the given groups
void fill( Instances::Groups const & );
};
#endif

BIN
src/icons/accents.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

BIN
src/icons/prefix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

BIN
src/icons/pushpin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

21
src/keyboardstate.cc Normal file
View file

@ -0,0 +1,21 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "keyboardstate.hh"
#include <QX11Info>
#include <X11/X.h>
#include <X11/XKBlib.h>
bool KeyboardState::checkModifiersPressed( int mask )
{
XkbStateRec state;
XkbGetState( QX11Info::display(), XkbUseCoreKbd, &state );
return !(
( mask & Alt && !( state.base_mods & Mod1Mask ) ) ||
( mask & Ctrl && !( state.base_mods & ControlMask ) ) ||
( mask & Shift && !( state.base_mods & ShiftMask ) ) ||
( mask & Win && !( state.base_mods & Mod4Mask ) ) );
}

27
src/keyboardstate.hh Normal file
View file

@ -0,0 +1,27 @@
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.sf.net>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#ifndef __KEYBOARDSTATE_HH_INCLUDED__
#define __KEYBOARDSTATE_HH_INCLUDED__
/// Since Qt doesn't provide a way to test for keyboard modifiers state
/// when the app isn't in focus, we have to implement this separately for
/// each platform.
class KeyboardState
{
public:
enum
{
Alt = 1,
Ctrl = 2,
Shift = 4,
Win = 8
} Modifier;
/// Returns true if all Modifiers present within the given mask are pressed
/// right now.
bool checkModifiersPressed( int mask );
};
#endif

View file

@ -3,12 +3,22 @@
#include <QApplication>
#include "mainwindow.hh"
#include "dictionary.hh"
#include "config.hh"
int main( int argc, char ** argv )
{
QApplication app( argc, argv );
// Try loading a style sheet if there's one
#if 1
QFile cssFile( Config::getUserQtCssFileName() );
if ( cssFile.open( QFile::ReadOnly ) )
app.setStyleSheet( cssFile.readAll() );
#endif
MainWindow m;
m.show();

View file

@ -27,7 +27,6 @@ MainWindow::MainWindow():
articleMaker( dictionaries, groupInstances ),
articleNetMgr( this, dictionaries, articleMaker ),
wordFinder( this ),
scanPopup( 0, articleNetMgr ),
initializing( 0 )
{
ui.setupUi( this );
@ -214,6 +213,7 @@ void MainWindow::makeDictionaries()
updateStatusLine();
updateGroupList();
makeScanPopup();
}
void MainWindow::updateStatusLine()
@ -239,24 +239,23 @@ void MainWindow::updateGroupList()
ui.groupLabel->setText( haveGroups ? tr( "Look up in:" ) : tr( "Look up:" ) );
ui.groupList->clear();
groupInstances.clear();
DictLock _;
for( unsigned x = 0; x < cfg.groups.size(); ++x )
{
groupInstances.push_back( Instances::Group( cfg.groups[ x ], dictionaries ) );
DictLock _;
QIcon icon = cfg.groups[ x ].icon.size() ?
QIcon( ":/flags/" + cfg.groups[ x ].icon ) : QIcon();
groupInstances.clear();
ui.groupList->addItem( icon, cfg.groups[ x ].name );
for( unsigned x = 0; x < cfg.groups.size(); ++x )
groupInstances.push_back( Instances::Group( cfg.groups[ x ], dictionaries ) );
}
if ( haveGroups )
ui.groupList->setCurrentIndex( 0 );
ui.groupList->fill( groupInstances );
}
void MainWindow::makeScanPopup()
{
scanPopup.reset();
scanPopup = new ScanPopup( 0, articleNetMgr, dictionaries, groupInstances );
}
vector< sptr< Dictionary::Class > > const & MainWindow::getActiveDicts()
@ -377,6 +376,7 @@ void MainWindow::editGroups()
}
updateGroupList();
makeScanPopup();
}
void MainWindow::translateInputChanged( QString const & newValue )

View file

@ -70,13 +70,14 @@ private:
WordFinder wordFinder;
ScanPopup scanPopup;
sptr< ScanPopup > scanPopup;
::Initializing * initializing;
void makeDictionaries();
void updateStatusLine();
void updateGroupList();
void makeScanPopup();
/// Returns the reference to dictionaries stored in the currently active
/// group, or to all dictionaries if there are no groups.

View file

@ -1,7 +1,8 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@ -9,44 +10,44 @@
<height>538</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>GoldenDict</string>
</property>
<widget class="QWidget" name="centralwidget" >
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="groupLabel" >
<property name="text" >
<widget class="QLabel" name="groupLabel">
<property name="text">
<string>Look up in:</string>
</property>
<property name="alignment" >
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="groupList" >
<property name="sizeAdjustPolicy" >
<widget class="GroupComboBox" name="groupList">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="duplicatesEnabled" >
<property name="duplicatesEnabled">
<bool>true</bool>
</property>
<property name="frame" >
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
@ -57,25 +58,25 @@
</layout>
</item>
<item>
<widget class="QLineEdit" name="translateLine" >
<property name="minimumSize" >
<widget class="QLineEdit" name="translateLine">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="baseSize" >
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="palette" >
<property name="palette">
<palette>
<active>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>254</red>
<green>253</green>
<blue>235</blue>
@ -84,9 +85,9 @@
</colorrole>
</active>
<inactive>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>254</red>
<green>253</green>
<blue>235</blue>
@ -95,9 +96,9 @@
</colorrole>
</inactive>
<disabled>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
@ -107,32 +108,32 @@
</disabled>
</palette>
</property>
<property name="frame" >
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget" >
<property name="lineWidth" >
<widget class="QStackedWidget" name="stackedWidget">
<property name="lineWidth">
<number>0</number>
</property>
<property name="currentIndex" >
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page" >
<layout class="QVBoxLayout" name="verticalLayout_3" >
<property name="margin" >
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="wordList" >
<property name="palette" >
<widget class="QListWidget" name="wordList">
<property name="palette">
<palette>
<active>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>254</red>
<green>253</green>
<blue>235</blue>
@ -141,9 +142,9 @@
</colorrole>
</active>
<inactive>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>254</red>
<green>253</green>
<blue>235</blue>
@ -152,9 +153,9 @@
</colorrole>
</inactive>
<disabled>
<colorrole role="Base" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
@ -168,31 +169,31 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" name="verticalLayout_4" >
<property name="margin" >
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget_2" >
<property name="tabPosition" >
<widget class="QTabWidget" name="tabWidget_2">
<property name="tabPosition">
<enum>QTabWidget::West</enum>
</property>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5" >
<property name="margin" >
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="listWidget" />
<widget class="QListWidget" name="listWidget"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3" >
<attribute name="title" >
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
@ -205,25 +206,25 @@
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget" >
<property name="currentIndex" >
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<property name="iconSize" >
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="elideMode" >
<property name="elideMode">
<enum>Qt::ElideRight</enum>
</property>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Welcome!</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_4" >
<property name="margin" >
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="margin">
<number>0</number>
</property>
</layout>
@ -231,56 +232,61 @@
</widget>
</item>
</layout>
<zorder>tabWidget</zorder>
<zorder>view</zorder>
</widget>
<widget class="QMenuBar" name="menubar" >
<property name="geometry" >
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>653</width>
<height>29</height>
<height>26</height>
</rect>
</property>
<widget class="QMenu" name="menuFile" >
<property name="title" >
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
</widget>
<widget class="QMenu" name="menu_Edit" >
<property name="title" >
<widget class="QMenu" name="menu_Edit">
<property name="title">
<string>&amp;Edit</string>
</property>
<addaction name="sources" />
<addaction name="groups" />
<addaction name="sources"/>
<addaction name="groups"/>
</widget>
<addaction name="menuFile" />
<addaction name="menu_Edit" />
<addaction name="menuFile"/>
<addaction name="menu_Edit"/>
</widget>
<widget class="QStatusBar" name="statusbar" />
<action name="action_Preferences" >
<property name="text" >
<widget class="QStatusBar" name="statusbar"/>
<action name="action_Preferences">
<property name="text">
<string>&amp;Preferences...</string>
</property>
</action>
<action name="sources" >
<property name="text" >
<action name="sources">
<property name="text">
<string>&amp;Sources...</string>
</property>
</action>
<action name="groups" >
<property name="text" >
<action name="groups">
<property name="text">
<string>&amp;Groups...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>GroupComboBox</class>
<extends>QComboBox</extends>
<header>groupcombobox.hh</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>translateLine</tabstop>
<tabstop>tabWidget</tabstop>
</tabstops>
<resources>
<include location="resources.qrc" />
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -1,5 +1,8 @@
<RCC>
<qresource>
<file>icons/accents.png</file>
<file>icons/prefix.png</file>
<file>icons/pushpin.png</file>
<file>icons/playsound.png</file>
<file>icons/closetab.png</file>
<file>icons/addtab.png</file>

View file

@ -2,49 +2,229 @@
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "scanpopup.hh"
#include "folding.hh"
#include <QUrl>
#include <QCursor>
#include <QPixmap>
#include <QBitmap>
#include <QMenu>
using std::wstring;
ScanPopup::ScanPopup( QWidget * parent,
ArticleNetworkAccessManager & articleNetMgr_ ):
QDialog( parent ), articleNetMgr( articleNetMgr_ )
ArticleNetworkAccessManager & articleNetMgr,
std::vector< sptr< Dictionary::Class > > const & allDictionaries_,
Instances::Groups const & groups_ ):
QDialog( parent ),
allDictionaries( allDictionaries_ ),
groups( groups_ ),
wordFinder( this )
{
ui.setupUi( this );
definition = new ArticleView( ui.outerFrame, articleNetMgr, groups, true ),
ui.mainLayout->addWidget( definition );
ui.diacriticButton->hide();
ui.prefixButton->hide();
ui.groupList->fill( groups );
//setWindowFlags( Qt::Tool );
setWindowFlags( Qt::Dialog | Qt::FramelessWindowHint | Qt::Tool );
ui.definition->page()->setNetworkAccessManager( &articleNetMgr );
#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
connect( ui.groupList, SIGNAL( currentIndexChanged( QString const & ) ),
this, SLOT( currentGroupChanged( QString const & ) ) );
connect( wordFinder.qobject(), SIGNAL( prefixMatchComplete( WordFinderResults ) ),
this, SLOT( prefixMatchComplete( WordFinderResults ) ) );
connect( ui.word, SIGNAL( clicked() ),
this, SLOT( initialWordClicked() ) );
connect( ui.diacriticButton, SIGNAL( clicked() ),
this, SLOT( diacriticButtonClicked() ) );
connect( ui.prefixButton, SIGNAL( clicked() ),
this, SLOT( prefixButtonClicked() ) );
connect( ui.pinButton, SIGNAL( clicked( bool ) ),
this, SLOT( pinButtonClicked( bool ) ) );
#if 0 // Since this is unconditional this bugs a lot
connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ),
this, SLOT( clipboardChanged( QClipboard::Mode ) ) );
#endif
}
void ScanPopup::clipboardChanged( QClipboard::Mode m )
{
printf( "clipboard changed\n" );
QString subtype = "plain";
// Check key modifiers
QString inWord = QApplication::clipboard()->text( subtype, m );
if ( !inWord.size() )
if ( !checkModifiersPressed( Ctrl ) )
return;
setWindowTitle( inWord );
QString subtype = "plain";
show();
activateWindow();
//raise();
inputWord = QApplication::clipboard()->text( subtype, m ).trimmed();
QUrl req;
if ( !inputWord.size() )
return;
req.setScheme( "gdlookup" );
req.setHost( "localhost" );
req.addQueryItem( "word", inWord );
req.addQueryItem( "group",
"whatever" );
setWindowTitle( inputWord );
ui.word->setText( inputWord );
ui.definition->load( req );
if ( !isVisible() )
{
QPoint currentPos = QCursor::pos();
move( currentPos.x() + 4, currentPos.y() + 10 );
show();
activateWindow();
QApplication::processEvents(); // Make window appear immediately no matter what
}
initiateTranslation();
}
void ScanPopup::currentGroupChanged( QString const & )
{
if ( isVisible() )
initiateTranslation();
}
void ScanPopup::initiateTranslation()
{
wordFinder.prefixMatch( inputWord, &getActiveDicts() );
}
vector< sptr< Dictionary::Class > > const & ScanPopup::getActiveDicts()
{
int currentGroup = ui.groupList->currentIndex();
return
currentGroup < 0 || currentGroup >= (int)groups.size() ? allDictionaries :
groups[ currentGroup ].dictionaries;
}
void ScanPopup::leaveEvent( QEvent * event )
{
QDialog::leaveEvent( event );
// We hide the popup when the mouse leaves it. So in order to close it
// without any clicking the cursor has to get inside and then to leave.
// Combo-boxes seem to generate leave events for their parents when
// unfolded, so we check coordinates as well.
// If the dialog is pinned, we don't hide the popup
if ( !ui.pinButton->isChecked() && !geometry().contains( QCursor::pos() ) )
hide();
}
void ScanPopup::prefixMatchComplete( WordFinderResults r )
{
// Check that the request wasn't already overridden by another one and
// that there's a window there at all
if ( isVisible() && r.requestStr == inputWord &&
r.requestDicts == &getActiveDicts() )
{
// Find the matches that aren't prefix. If there're more than one,
// show the diacritic toolbutton. If there are prefix matches, show
// the prefix toolbutton.
diacriticMatches.clear();
prefixMatches.clear();
wstring foldedInputWord = Folding::apply( inputWord.toStdWString() );
for( unsigned x = 0; x < r.results.size(); ++x )
{
if ( Folding::apply( r.results[ x ].toStdWString() ) == foldedInputWord )
diacriticMatches.push_back( r.results[ x ] );
else
prefixMatches.push_back( r.results[ x ] );
}
if ( diacriticMatches.size() > 1 )
{
ui.diacriticButton->setToolTip( tr( "%1 results differing in diacritic marks" ).arg( diacriticMatches.size() ) );
ui.diacriticButton->show();
}
else
ui.diacriticButton->hide();
if ( prefixMatches.size() )
{
ui.prefixButton->setToolTip( tr( "%1 result(s) beginning with the search word" ).arg( prefixMatches.size() ) );
ui.prefixButton->show();
}
else
ui.prefixButton->hide();
if ( diacriticMatches.size() )
definition->showDefinition( diacriticMatches[ 0 ], ui.groupList->currentText() );
else
{
// No matches
definition->showNotFound( inputWord, ui.groupList->currentText() );
}
}
}
void ScanPopup::diacriticButtonClicked()
{
popupWordlist( diacriticMatches, ui.diacriticButton );
}
void ScanPopup::prefixButtonClicked()
{
popupWordlist( prefixMatches, ui.prefixButton );
}
void ScanPopup::popupWordlist( vector< QString > const & words, QToolButton * button )
{
if ( !isVisible() )
return;
if ( words.empty() )
return;
QMenu menu( this );
for( unsigned x = 0; x < words.size(); ++x )
menu.addAction( words[ x ] );
QAction * result = menu.exec( mapToGlobal( button->pos() ) +
QPoint( 0, button->height() ) );
if ( result )
definition->showDefinition( result->text(), ui.groupList->currentText() );
}
void ScanPopup::initialWordClicked()
{
if ( isVisible() && diacriticMatches.size() )
definition->showDefinition( diacriticMatches[ 0 ], ui.groupList->currentText() );
}
void ScanPopup::pinButtonClicked( bool checked )
{
if ( checked )
setWindowFlags( Qt::Dialog );
else
setWindowFlags( Qt::Dialog | Qt::FramelessWindowHint | Qt::Tool );
// Should we disable grip? I like it with the grip better.
//ui.gripArea->setDisabled( checked );
show();
}

View file

@ -5,26 +5,54 @@
#define __SCANPOPUP_HH_INCLUDED__
#include "article_netmgr.hh"
#include "articleview.hh"
#include "wordfinder.hh"
#include "keyboardstate.hh"
#include "ui_scanpopup.h"
#include <QDialog>
#include <QClipboard>
class ScanPopup: public QDialog
/// This is a popup dialog to show translations when clipboard scanning mode
/// is enabled.
class ScanPopup: public QDialog, KeyboardState
{
Q_OBJECT
public:
ScanPopup( QWidget * parent, ArticleNetworkAccessManager & articleNetMgr );
ScanPopup( QWidget * parent,
ArticleNetworkAccessManager &,
std::vector< sptr< Dictionary::Class > > const & allDictionaries,
Instances::Groups const & );
private:
ArticleNetworkAccessManager & articleNetMgr;
std::vector< sptr< Dictionary::Class > > const & allDictionaries;
Instances::Groups const & groups;
Ui::ScanPopup ui;
ArticleView * definition;
QString inputWord;
WordFinder wordFinder;
vector< QString > diacriticMatches, prefixMatches;
void initiateTranslation();
vector< sptr< Dictionary::Class > > const & getActiveDicts();
virtual void leaveEvent( QEvent * event );
void popupWordlist( vector< QString > const &, QToolButton * button );
private slots:
void clipboardChanged( QClipboard::Mode );
void currentGroupChanged( QString const & );
void prefixMatchComplete( WordFinderResults r );
void diacriticButtonClicked();
void prefixButtonClicked();
void initialWordClicked();
void pinButtonClicked( bool checked );
};
#endif

View file

@ -1,67 +1,144 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScanPopup</class>
<widget class="QDialog" name="ScanPopup" >
<property name="geometry" >
<widget class="QDialog" name="ScanPopup">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>557</width>
<height>403</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QToolButton" name="toolButton" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_2" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QWebView" name="definition" >
<property name="url" >
<url>
<string>about:blank</string>
</url>
<widget class="QFrame" name="outerFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="mainLayout">
<property name="margin">
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="GroupComboBox" name="groupList"/>
</item>
<item>
<widget class="QToolButton" name="word">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>word</string>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="diacriticButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/accents.png</normaloff>:/icons/accents.png</iconset>
</property>
<property name="iconSize">
<size>
<width>22</width>
<height>16</height>
</size>
</property>
<property name="arrowType">
<enum>Qt::NoArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="prefixButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/prefix.png</normaloff>:/icons/prefix.png</iconset>
</property>
<property name="iconSize">
<size>
<width>22</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="GripArea" name="gripArea" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="pinButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/pushpin.png</normaloff>:/icons/pushpin.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QWebView</class>
<class>GroupComboBox</class>
<extends>QComboBox</extends>
<header>groupcombobox.hh</header>
</customwidget>
<customwidget>
<class>GripArea</class>
<extends>QWidget</extends>
<header>QtWebKit/QWebView</header>
<header>griparea.hh</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>