mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 15:24:05 +00:00
+ History of search queries implemented.
This commit is contained in:
parent
2c46854ab1
commit
9ee8210c1f
|
@ -119,7 +119,9 @@ HEADERS += folding.hh \
|
|||
orderandprops.hh \
|
||||
language.hh \
|
||||
dictionarybar.hh \
|
||||
broken_xrecord.hh
|
||||
broken_xrecord.hh \
|
||||
history.hh \
|
||||
atomic_rename.hh
|
||||
FORMS += groups.ui \
|
||||
dictgroupwidget.ui \
|
||||
mainwindow.ui \
|
||||
|
@ -190,7 +192,9 @@ SOURCES += folding.cc \
|
|||
orderandprops.cc \
|
||||
language.cc \
|
||||
dictionarybar.cc \
|
||||
broken_xrecord.cc
|
||||
broken_xrecord.cc \
|
||||
history.cc \
|
||||
atomic_rename.cc
|
||||
win32 {
|
||||
SOURCES += mouseover_win32/ThTypes.c
|
||||
HEADERS += mouseover_win32/ThTypes.h
|
||||
|
@ -201,7 +205,8 @@ TRANSLATIONS += locale/ru_RU.ts \
|
|||
locale/zh_CN.ts \
|
||||
locale/cs_CZ.ts \
|
||||
locale/de_DE.ts \
|
||||
locale/el_GR.ts
|
||||
locale/el_GR.ts \
|
||||
locale/bg_BG.ts
|
||||
|
||||
# This makes qmake generate translations
|
||||
isEmpty(QMAKE_LRELEASE):QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
|
||||
|
|
101
src/history.cc
Normal file
101
src/history.cc
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.berlios.de>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "history.hh"
|
||||
#include "config.hh"
|
||||
#include "atomic_rename.hh"
|
||||
#include <QFile>
|
||||
|
||||
History::History( unsigned size ): maxSize( size )
|
||||
{
|
||||
}
|
||||
|
||||
History::History( Load, unsigned size ): maxSize( size )
|
||||
{
|
||||
QFile file( Config::getHistoryFileName() );
|
||||
|
||||
if ( !file.open( QFile::ReadOnly | QIODevice::Text ) )
|
||||
return; // No file -- no history
|
||||
|
||||
for( unsigned count = 0 ; count < maxSize; ++count )
|
||||
{
|
||||
QByteArray lineUtf8 = file.readLine( 4096 );
|
||||
|
||||
if ( lineUtf8.isEmpty() )
|
||||
break;
|
||||
|
||||
if ( lineUtf8.endsWith( '\n' ) )
|
||||
lineUtf8.chop( 1 );
|
||||
|
||||
QString line = QString::fromUtf8( lineUtf8 );
|
||||
|
||||
int firstSpace = line.indexOf( ' ' );
|
||||
|
||||
if ( firstSpace < 0 )
|
||||
// No spaces? Bad line. End this.
|
||||
break;
|
||||
|
||||
bool isNumber;
|
||||
|
||||
unsigned groupId = line.left( firstSpace ).toUInt( &isNumber, 10 );
|
||||
|
||||
if ( !isNumber )
|
||||
break; // That's not right
|
||||
|
||||
items.push_back( Item( groupId, line.right( line.size() - firstSpace - 1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void History::addItem( Item const & item )
|
||||
{
|
||||
if ( items.contains( item ) )
|
||||
items.removeAll( item );
|
||||
|
||||
// Special case: if this items differs from the previous one only by group,
|
||||
// remove it too.
|
||||
|
||||
if ( items.size() && items.first().word == item.word )
|
||||
items.pop_front();
|
||||
|
||||
items.push_front( item );
|
||||
|
||||
while( items.size() > (int)maxSize )
|
||||
items.pop_back();
|
||||
|
||||
emit itemsChanged();
|
||||
}
|
||||
|
||||
bool History::save() const
|
||||
{
|
||||
QFile file( Config::getHistoryFileName() + ".tmp" );
|
||||
|
||||
if ( !file.open( QFile::WriteOnly | QIODevice::Text ) )
|
||||
return false;
|
||||
|
||||
for( QList< Item >::const_iterator i = items.constBegin();
|
||||
i != items.constEnd(); ++i )
|
||||
{
|
||||
QByteArray line = i->word.toUtf8();
|
||||
|
||||
// Those could ruin our format, so we replace them by spaces. They shouldn't
|
||||
// be there anyway.
|
||||
line.replace( '\n', ' ' );
|
||||
line.replace( '\r', ' ' );
|
||||
|
||||
line = QByteArray::number( i->groupId ) + " " + line + "\n";
|
||||
|
||||
if ( file.write( line ) != line.size() )
|
||||
return false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return renameAtomically( file.fileName(), Config::getHistoryFileName() );
|
||||
}
|
||||
|
||||
void History::clear()
|
||||
{
|
||||
items.clear();
|
||||
|
||||
emit itemsChanged();
|
||||
}
|
78
src/history.hh
Normal file
78
src/history.hh
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* This file is (c) 2008-2009 Konstantin Isakov <ikm@users.berlios.de>
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#ifndef __HISTORY_HH_INCLUDED__
|
||||
#define __HISTORY_HH_INCLUDED__
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
/// Search history
|
||||
class History: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/// An item in history
|
||||
struct Item
|
||||
{
|
||||
/// Group the search was perfomed in
|
||||
unsigned groupId;
|
||||
/// The word that was searched
|
||||
QString word;
|
||||
|
||||
Item(): groupId( 0 )
|
||||
{}
|
||||
|
||||
Item( unsigned groupId_, QString const & word_ ):
|
||||
groupId( groupId_ ), word( word_ )
|
||||
{}
|
||||
|
||||
bool operator == ( Item const & other ) const
|
||||
{ return word == other.word && groupId == other.groupId; }
|
||||
|
||||
bool operator != ( Item const & other ) const
|
||||
{ return ! operator == ( other ); }
|
||||
};
|
||||
|
||||
/// Indicates an intention to load -- see the relevant History constructor.
|
||||
struct Load {};
|
||||
|
||||
/// Constructs an empty history which can hold at most "size" items.
|
||||
History( unsigned size = 20 );
|
||||
|
||||
/// Loads history from its file. If load fails, the result would be an empty
|
||||
/// history. The size parameter is same as in other constructor.
|
||||
History( Load, unsigned size = 20 );
|
||||
|
||||
/// Adds new item. The item is always added at the beginning of the list.
|
||||
/// If there was such an item already somewhere on the list, it gets removed
|
||||
/// from there. If otherwise the resulting list gets too large, the oldest
|
||||
/// item gets removed from the end of the list.
|
||||
void addItem( Item const & );
|
||||
|
||||
/// Attempts saving history. Returns true if succeeded - false otherwise.
|
||||
/// Since history isn't really that valuable, failures can be ignored.
|
||||
bool save() const;
|
||||
|
||||
/// Clears history.
|
||||
void clear();
|
||||
|
||||
/// Gets the current items. The first one is the newest one on the list.
|
||||
QList< Item > const & getItems() const
|
||||
{ return items; }
|
||||
|
||||
signals:
|
||||
|
||||
/// Signals the changes in items in response to addItem() or clear().
|
||||
void itemsChanged();
|
||||
|
||||
private:
|
||||
|
||||
QList< Item > items;
|
||||
unsigned maxSize;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -34,6 +34,7 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
trayIconMenu( this ),
|
||||
addTab( this ),
|
||||
cfg( cfg_ ),
|
||||
history( History::Load() ),
|
||||
dictionaryBar( this, cfg.mutedDictionaries, configEvents ),
|
||||
articleMaker( dictionaries, groupInstances, cfg.preferences.displayStyle ),
|
||||
articleNetMgr( this, dictionaries, articleMaker,
|
||||
|
@ -181,6 +182,11 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
connect( dictionaryBar.toggleViewAction(), SIGNAL(toggled(bool)),
|
||||
this, SLOT(dictionaryBarToggled(bool)) );
|
||||
|
||||
// History
|
||||
|
||||
connect( &history, SIGNAL( itemsChanged() ),
|
||||
this, SLOT( historyChanged() ) );
|
||||
|
||||
// Show tray icon early so the user would be happy. It won't be functional
|
||||
// though until the program inits fully.
|
||||
|
||||
|
@ -274,6 +280,9 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
|
|||
|
||||
makeDictionaries();
|
||||
|
||||
// After we have dictionaries and groups, we can populate history
|
||||
historyChanged();
|
||||
|
||||
addNewTab();
|
||||
|
||||
// Show the initial welcome text
|
||||
|
@ -569,7 +578,8 @@ void MainWindow::makeScanPopup()
|
|||
!cfg.preferences.enableClipboardHotkey )
|
||||
return;
|
||||
|
||||
scanPopup = new ScanPopup( 0, cfg, articleNetMgr, dictionaries, groupInstances );
|
||||
scanPopup = new ScanPopup( 0, cfg, articleNetMgr, dictionaries, groupInstances,
|
||||
history );
|
||||
|
||||
scanPopup->setStyleSheet( styleSheet() );
|
||||
|
||||
|
@ -1111,18 +1121,28 @@ void MainWindow::mutedDictionariesChanged()
|
|||
applyMutedDictionariesState();
|
||||
}
|
||||
|
||||
void MainWindow::showTranslationFor( QString const & inWord )
|
||||
void MainWindow::showTranslationFor( QString const & inWord,
|
||||
int inGroup )
|
||||
{
|
||||
ArticleView & view =
|
||||
dynamic_cast< ArticleView & >( *( ui.tabWidget->currentWidget() ) );
|
||||
|
||||
navPronounce->setEnabled( false );
|
||||
|
||||
view.showDefinition( inWord, groupInstances.empty() ? 0 :
|
||||
groupInstances[ groupList.currentIndex() ].id );
|
||||
unsigned group = inGroup < 0 ?
|
||||
( groupInstances.empty() ? 0 :
|
||||
groupInstances[ groupList.currentIndex() ].id ):
|
||||
inGroup;
|
||||
|
||||
view.showDefinition( inWord, group );
|
||||
|
||||
updatePronounceAvailability();
|
||||
|
||||
// Add to history
|
||||
|
||||
history.addItem( History::Item( group, inWord.trimmed() ) );
|
||||
history.save();
|
||||
|
||||
#if 0
|
||||
QUrl req;
|
||||
|
||||
|
@ -1483,6 +1503,56 @@ void MainWindow::showDictBarNamesTriggered()
|
|||
cfg.showingDictBarNames = show;
|
||||
}
|
||||
|
||||
void MainWindow::historyChanged()
|
||||
{
|
||||
// Rebuild history menu
|
||||
|
||||
ui.menuHistory->clear();
|
||||
|
||||
QList< History::Item > const & items = history.getItems();
|
||||
|
||||
for( int x = 0; x < items.size(); ++x )
|
||||
{
|
||||
History::Item const * i = &items[ x ];
|
||||
|
||||
Instances::Group const * group = groupInstances.findGroup( i->groupId );
|
||||
|
||||
QIcon icon = group ? group->makeIcon() : QIcon();
|
||||
|
||||
QAction * action = ui.menuHistory->addAction( icon, i->word );
|
||||
|
||||
action->setData( x );
|
||||
}
|
||||
|
||||
ui.menuHistory->addSeparator();
|
||||
|
||||
ui.menuHistory->addAction( ui.clearHistory );
|
||||
|
||||
ui.clearHistory->setEnabled( items.size() );
|
||||
}
|
||||
|
||||
void MainWindow::on_menuHistory_triggered( QAction * action )
|
||||
{
|
||||
if ( action->data().type() != QVariant::Int )
|
||||
return; // Not the item we added
|
||||
|
||||
int index = action->data().toInt();
|
||||
|
||||
QList< History::Item > const & items = history.getItems();
|
||||
|
||||
if ( index < 0 || index >= items.size() )
|
||||
return; // Something's not right
|
||||
|
||||
History::Item const & item = items[ index ];
|
||||
|
||||
showTranslationFor( item.word, item.groupId );
|
||||
}
|
||||
|
||||
void MainWindow::on_clearHistory_activated()
|
||||
{
|
||||
history.clear();
|
||||
}
|
||||
|
||||
void MainWindow::setAutostart(bool autostart)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "wordfinder.hh"
|
||||
#include "hotkeywrapper.hh"
|
||||
#include "dictionarybar.hh"
|
||||
#include "history.hh"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -56,6 +57,7 @@ private:
|
|||
QToolButton addTab;
|
||||
Config::Class & cfg;
|
||||
Config::Events configEvents;
|
||||
History history;
|
||||
DictionaryBar dictionaryBar;
|
||||
vector< sptr< Dictionary::Class > > dictionaries;
|
||||
/// Here we store unmuted dictionaries when the dictionary bar is active
|
||||
|
@ -200,7 +202,7 @@ private slots:
|
|||
|
||||
void mutedDictionariesChanged();
|
||||
|
||||
void showTranslationFor( QString const & );
|
||||
void showTranslationFor( QString const &, int inGroup = -1 );
|
||||
|
||||
void trayIconActivated( QSystemTrayIcon::ActivationReason );
|
||||
|
||||
|
@ -216,6 +218,10 @@ private slots:
|
|||
|
||||
void showDictBarNamesTriggered();
|
||||
|
||||
void historyChanged();
|
||||
void on_menuHistory_triggered( QAction * );
|
||||
void on_clearHistory_activated();
|
||||
|
||||
void on_actionCloseToTray_activated();
|
||||
|
||||
void on_pageSetup_activated();
|
||||
|
|
|
@ -97,9 +97,17 @@
|
|||
<string>&View</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHistory">
|
||||
<property name="title">
|
||||
<string>&History</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="clearHistory"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menu_Edit"/>
|
||||
<addaction name="menuHistory"/>
|
||||
<addaction name="menu_Help"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
|
@ -354,6 +362,11 @@
|
|||
<string>Ctrl+F5</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="clearHistory">
|
||||
<property name="text">
|
||||
<string>&Clear</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -19,12 +19,14 @@ ScanPopup::ScanPopup( QWidget * parent,
|
|||
Config::Class & cfg_,
|
||||
ArticleNetworkAccessManager & articleNetMgr,
|
||||
std::vector< sptr< Dictionary::Class > > const & allDictionaries_,
|
||||
Instances::Groups const & groups_ ):
|
||||
Instances::Groups const & groups_,
|
||||
History & history_ ):
|
||||
QDialog( parent ),
|
||||
cfg( cfg_ ),
|
||||
isScanningEnabled( false ),
|
||||
allDictionaries( allDictionaries_ ),
|
||||
groups( groups_ ),
|
||||
history( history_ ),
|
||||
escapeAction( this ),
|
||||
wordFinder( this ),
|
||||
mouseEnteredOnce( false ),
|
||||
|
@ -294,6 +296,10 @@ void ScanPopup::initiateTranslation()
|
|||
|
||||
definition->showDefinition( inputWord, ui.groupList->getCurrentGroup() );
|
||||
wordFinder.prefixMatch( inputWord, getActiveDicts() );
|
||||
|
||||
history.addItem( History::Item( ui.groupList->getCurrentGroup(),
|
||||
inputWord.trimmed() ) );
|
||||
history.save();
|
||||
}
|
||||
|
||||
vector< sptr< Dictionary::Class > > const & ScanPopup::getActiveDicts()
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "ui_scanpopup.h"
|
||||
#include <QDialog>
|
||||
#include <QClipboard>
|
||||
#include "history.hh"
|
||||
|
||||
/// This is a popup dialog to show translations when clipboard scanning mode
|
||||
/// is enabled.
|
||||
|
@ -25,7 +26,8 @@ public:
|
|||
Config::Class & cfg,
|
||||
ArticleNetworkAccessManager &,
|
||||
std::vector< sptr< Dictionary::Class > > const & allDictionaries,
|
||||
Instances::Groups const & );
|
||||
Instances::Groups const &,
|
||||
History & );
|
||||
|
||||
~ScanPopup();
|
||||
|
||||
|
@ -55,6 +57,7 @@ private:
|
|||
bool isScanningEnabled;
|
||||
std::vector< sptr< Dictionary::Class > > const & allDictionaries;
|
||||
Instances::Groups const & groups;
|
||||
History & history;
|
||||
Ui::ScanPopup ui;
|
||||
ArticleView * definition;
|
||||
QAction escapeAction;
|
||||
|
|
Loading…
Reference in a new issue