diff --git a/src/article_maker.cc b/src/article_maker.cc
index c28fdd67..f38a7f46 100644
--- a/src/article_maker.cc
+++ b/src/article_maker.cc
@@ -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 =
"
"
"";
@@ -42,7 +38,24 @@ string ArticleMaker::makeDefinitionFor( QString const & inWord,
result += "\n";
}
- result += "" + Html::escape( Utf8::encode( word ) ) + "";
+ result += "" + Html::escape( Utf8::encode( word.toStdWString() ) ) + "";
+
+ // This doesn't seem to be much of influence right now, but we'll keep
+ // it anyway.
+ if ( icon.size() )
+ result += "\n";
+
+ result += "";
+
+ 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 += "icon.toUtf8().data() ) + "\" />\n";
- }
-
- result += "";
+ 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 += "From " + Html::escape( activeDicts[ x ]->getName() ) + "
" + body;
+ result += string( "" ) +
+ tr( "From " ).toUtf8().data() +
+ Html::escape( activeDicts[ x ]->getName() ) + "
" + 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() ) +
+ "" +
+ tr( "No translation for %1 was found in group %2." ).
+ arg( QString::fromUtf8( Html::escape( word.toUtf8().data() ).c_str() ) ).
+ arg( QString::fromUtf8(Html::escape( group.toUtf8().data() ).c_str() ) ).
+ toUtf8().data()
+ +"
"
+ "";
+}
diff --git a/src/article_maker.hh b/src/article_maker.hh
index 98407557..7e041820 100644
--- a/src/article_maker.hh
+++ b/src/article_maker.hh
@@ -4,12 +4,15 @@
#ifndef __ARTICLE_MAKER_HH_INCLUDED__
#define __ARTICLE_MAKER_HH_INCLUDED__
+#include
#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
diff --git a/src/article_netmgr.cc b/src/article_netmgr.cc
index 9d0cc0b1..bb6cf79e 100644
--- a/src/article_netmgr.cc
+++ b/src/article_netmgr.cc
@@ -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() );
diff --git a/src/articleview.cc b/src/articleview.cc
index e2c50518..11e0a7fc 100644
--- a/src/articleview.cc
+++ b/src/articleview.cc
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
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 )
diff --git a/src/articleview.hh b/src/articleview.hh
index 165f6b84..27078ea0 100644
--- a/src/articleview.hh
+++ b/src/articleview.hh
@@ -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(); }
diff --git a/src/config.cc b/src/config.cc
index 5aee230f..2d9b4b0f 100644
--- a/src/config.cc
+++ b/src/config.cc
@@ -200,4 +200,9 @@ QString getUserCssFileName() throw( exError )
return getHomeDir().filePath( "style.css" );
}
+QString getUserQtCssFileName() throw( exError )
+{
+ return getHomeDir().filePath( "qt-style.css" );
+}
+
}
diff --git a/src/config.hh b/src/config.hh
index ceb83c48..4a2d20d2 100644
--- a/src/config.hh
+++ b/src/config.hh
@@ -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
diff --git a/src/goldendict.pro b/src/goldendict.pro
index 10942e28..208cf1e9 100644
--- a/src/goldendict.pro
+++ b/src/goldendict.pro
@@ -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
diff --git a/src/griparea.cc b/src/griparea.cc
new file mode 100644
index 00000000..a81c359c
--- /dev/null
+++ b/src/griparea.cc
@@ -0,0 +1,53 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
+
+#include "griparea.hh"
+#include
+
+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 );
+}
diff --git a/src/griparea.hh b/src/griparea.hh
new file mode 100644
index 00000000..522283b9
--- /dev/null
+++ b/src/griparea.hh
@@ -0,0 +1,32 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
+
+#ifndef __GRIPAREA_HH_INCLUDED__
+#define __GRIPAREA_HH_INCLUDED__
+
+#include
+#include
+#include
+
+/// 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
diff --git a/src/groupcombobox.cc b/src/groupcombobox.cc
new file mode 100644
index 00000000..47f96e91
--- /dev/null
+++ b/src/groupcombobox.cc
@@ -0,0 +1,28 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * 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 );
+ }
+}
+
diff --git a/src/groupcombobox.hh b/src/groupcombobox.hh
new file mode 100644
index 00000000..84d68413
--- /dev/null
+++ b/src/groupcombobox.hh
@@ -0,0 +1,24 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
+
+#ifndef __GROUPCOMBOBOX_HH_INCLUDED__
+#define __GROUPCOMBOBOX_HH_INCLUDED__
+
+#include
+#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
+
diff --git a/src/icons/accents.png b/src/icons/accents.png
new file mode 100644
index 00000000..e7924360
Binary files /dev/null and b/src/icons/accents.png differ
diff --git a/src/icons/prefix.png b/src/icons/prefix.png
new file mode 100644
index 00000000..c7b98329
Binary files /dev/null and b/src/icons/prefix.png differ
diff --git a/src/icons/pushpin.png b/src/icons/pushpin.png
new file mode 100644
index 00000000..accac87d
Binary files /dev/null and b/src/icons/pushpin.png differ
diff --git a/src/keyboardstate.cc b/src/keyboardstate.cc
new file mode 100644
index 00000000..f217c682
--- /dev/null
+++ b/src/keyboardstate.cc
@@ -0,0 +1,21 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
+
+#include "keyboardstate.hh"
+#include
+#include
+#include
+
+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 ) ) );
+}
+
diff --git a/src/keyboardstate.hh b/src/keyboardstate.hh
new file mode 100644
index 00000000..9355bed8
--- /dev/null
+++ b/src/keyboardstate.hh
@@ -0,0 +1,27 @@
+/* This file is (c) 2008-2009 Konstantin Isakov
+ * 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
diff --git a/src/main.cc b/src/main.cc
index 8503c488..46649528 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -3,12 +3,22 @@
#include
#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();
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index 946dc104..d7ea0745 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -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 ) );
-
- QIcon icon = cfg.groups[ x ].icon.size() ?
- QIcon( ":/flags/" + cfg.groups[ x ].icon ) : QIcon();
-
- ui.groupList->addItem( icon, cfg.groups[ x ].name );
+ DictLock _;
+
+ groupInstances.clear();
+
+ 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 )
diff --git a/src/mainwindow.hh b/src/mainwindow.hh
index 7f93d6af..98d34dc1 100644
--- a/src/mainwindow.hh
+++ b/src/mainwindow.hh
@@ -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.
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index b1f77c17..943311fe 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -1,7 +1,8 @@
-
+
+
MainWindow
-
-
+
+
0
0
@@ -9,44 +10,44 @@
538
-
+
GoldenDict
-
-
+
+
-
-
+
-
-
+
-
-
-
+
+
Look up in:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
+
+
QComboBox::AdjustToContents
-
+
true
-
+
true
-
-
-
+
+
Qt::Horizontal
-
+
40
20
@@ -57,25 +58,25 @@
-
-
-
+
+
200
0
-
+
0
0
-
+
-
-
-
+
+
+
254
253
235
@@ -84,9 +85,9 @@
-
-
-
+
+
+
254
253
235
@@ -95,9 +96,9 @@
-
-
-
+
+
+
255
255
255
@@ -107,32 +108,32 @@
-
+
true
-
-
-
+
+
0
-
+
0
-
-
-
+
+
+
0
-
-
-
+
+
-
-
-
+
+
+
254
253
235
@@ -141,9 +142,9 @@
-
-
-
+
+
+
254
253
235
@@ -152,9 +153,9 @@
-
-
-
+
+
+
255
255
255
@@ -168,31 +169,31 @@
-
-
-
+
+
+
0
-
-
-
+
+
QTabWidget::West
-
-
+
+
Tab 1
-
-
+
+
0
-
-
+
-
-
+
+
Tab 2
@@ -205,25 +206,25 @@
-
-
-
+
+
0
-
+
16
16
-
+
Qt::ElideRight
-
-
+
+
Welcome!
-
-
+
+
0
@@ -231,56 +232,61 @@
- tabWidget
- view
-
diff --git a/src/resources.qrc b/src/resources.qrc
index cb4c6939..2e7c92d6 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -1,5 +1,8 @@
+ icons/accents.png
+ icons/prefix.png
+ icons/pushpin.png
icons/playsound.png
icons/closetab.png
icons/addtab.png
diff --git a/src/scanpopup.cc b/src/scanpopup.cc
index 1be8d790..3a0f43df 100644
--- a/src/scanpopup.cc
+++ b/src/scanpopup.cc
@@ -2,49 +2,229 @@
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include "scanpopup.hh"
+#include "folding.hh"
#include
+#include
+#include
+#include
+#include
+
+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();
+}
diff --git a/src/scanpopup.hh b/src/scanpopup.hh
index e8489232..e80c9902 100644
--- a/src/scanpopup.hh
+++ b/src/scanpopup.hh
@@ -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
#include
-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
diff --git a/src/scanpopup.ui b/src/scanpopup.ui
index b6e83f58..11373f36 100644
--- a/src/scanpopup.ui
+++ b/src/scanpopup.ui
@@ -1,67 +1,144 @@
-
+
+
ScanPopup
-
-
+
+
0
0
- 400
- 300
+ 557
+ 403
-
+
Dialog
-
+
+
+ 0
+
-
-
-
-
-
-
- ...
-
-
-
- -
-
-
- ...
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
- about:blank
-
+
+
+ QFrame::NoFrame
+
+ QFrame::Raised
+
+
+ 0
+
+
+
+ 9
+
+
-
+
+
-
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ word
+
+
+ true
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/accents.png:/icons/accents.png
+
+
+
+ 22
+ 16
+
+
+
+ Qt::NoArrow
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/prefix.png:/icons/prefix.png
+
+
+
+ 22
+ 16
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/icons/pushpin.png:/icons/pushpin.png
+
+
+ true
+
+
+ true
+
+
+
+
+
+
- QWebView
+ GroupComboBox
+ QComboBox
+
+
+
+ GripArea
QWidget
-
+
+ 1
-
+
+
+