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 - - + + 0 0 653 - 29 + 26 - - + + &File - - + + &Edit - - + + - - + + - - - + + + &Preferences... - - + + &Sources... - - + + &Groups... + + + GroupComboBox + QComboBox +
groupcombobox.hh
+
+
translateLine tabWidget - +
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 +
groupcombobox.hh
+
+ + GripArea QWidget -
QtWebKit/QWebView
+
griparea.hh
+ 1
- + + +