mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
Show all headwords for selected dictionary
This commit is contained in:
parent
becc74c730
commit
4a4bfade1d
127
btreeidx.cc
127
btreeidx.cc
|
@ -38,6 +38,7 @@ namespace BtreeIndexing {
|
|||
|
||||
using gd::wstring;
|
||||
using gd::wchar;
|
||||
using std::pair;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -709,8 +710,6 @@ vector< WordArticleLink > BtreeIndex::readChain( char const * & ptr )
|
|||
|
||||
vector< WordArticleLink > result;
|
||||
|
||||
vector< char > charBuffer;
|
||||
|
||||
while( chainSize )
|
||||
{
|
||||
string str = ptr;
|
||||
|
@ -1073,4 +1072,128 @@ IndexInfo buildIndex( IndexedWords const & indexedWords, File::Class & file )
|
|||
return IndexInfo( btreeMaxElements, rootOffset );
|
||||
}
|
||||
|
||||
void BtreeIndex::getAllHeadwords( QSet< QString > & headwords )
|
||||
{
|
||||
if ( !idxFile )
|
||||
throw exIndexWasNotOpened();
|
||||
|
||||
Mutex::Lock _( *idxFileMutex );
|
||||
|
||||
findNodeArticleLinks( rootOffset, NULL, NULL, &headwords );
|
||||
}
|
||||
|
||||
void BtreeIndex::findAllArticleLinks( QVector< FTSLink > & articleLinks )
|
||||
{
|
||||
if ( !idxFile )
|
||||
throw exIndexWasNotOpened();
|
||||
|
||||
Mutex::Lock _( *idxFileMutex );
|
||||
|
||||
QSet< uint32_t > offsets;
|
||||
|
||||
findNodeArticleLinks( rootOffset, &articleLinks, &offsets, NULL );
|
||||
}
|
||||
|
||||
void BtreeIndex::findNodeArticleLinks( uint32_t currentNodeOffset,
|
||||
QVector< FTSLink > * articleLinks,
|
||||
QSet< uint32_t > * offsets,
|
||||
QSet< QString > * headwords )
|
||||
{
|
||||
// Read a node
|
||||
|
||||
vector< char > extLeaf;
|
||||
|
||||
if( rootNodeLoaded && currentNodeOffset == rootOffset )
|
||||
extLeaf = rootNode;
|
||||
else
|
||||
readNode( currentNodeOffset, extLeaf );
|
||||
|
||||
char const * leaf = &extLeaf.front();
|
||||
|
||||
// Is it a leaf or a node?
|
||||
|
||||
uint32_t leafEntries = *(uint32_t *)leaf;
|
||||
|
||||
if ( leafEntries == 0xffffFFFF )
|
||||
{
|
||||
// A node
|
||||
|
||||
uint32_t const * offs = (uint32_t *)leaf + 1;
|
||||
|
||||
for( unsigned i = 0; i <= indexNodeSize; i++ )
|
||||
findNodeArticleLinks( offs[ i ], articleLinks, offsets, headwords );
|
||||
}
|
||||
else
|
||||
{
|
||||
// A leaf
|
||||
|
||||
if ( !leafEntries )
|
||||
{
|
||||
// Empty leaf? This may only be possible for entirely empty trees only.
|
||||
if ( currentNodeOffset != rootOffset )
|
||||
throw exCorruptedChainData();
|
||||
else
|
||||
return; // No match
|
||||
}
|
||||
|
||||
// Build an array containing all chain pointers
|
||||
char const * ptr = leaf + sizeof( uint32_t );
|
||||
|
||||
uint32_t chainSize;
|
||||
QPair< QSet< uint32_t >::iterator, bool > pr;
|
||||
|
||||
while( leafEntries-- )
|
||||
{
|
||||
memcpy( &chainSize, ptr, sizeof( uint32_t ) );
|
||||
|
||||
char const * chainPtr = ptr;
|
||||
vector< WordArticleLink > result = readChain( chainPtr );
|
||||
for( unsigned i = 0; i < result.size(); i++ )
|
||||
{
|
||||
if( headwords )
|
||||
headwords->insert( QString::fromUtf8( ( result[ i ].prefix + result[ i ].word ).c_str() ) );
|
||||
|
||||
if( !offsets || offsets->contains( result[ i ].articleOffset ) )
|
||||
continue;
|
||||
|
||||
offsets->insert( result[ i ].articleOffset );
|
||||
if( articleLinks )
|
||||
articleLinks->push_back( FTSLink( result[ i ].prefix + result[ i ].word, result[ i ].articleOffset ) );
|
||||
}
|
||||
|
||||
ptr += sizeof( uint32_t ) + chainSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BtreeDictionary::getHeadwords( QStringList &headwords )
|
||||
{
|
||||
QSet< QString > setOfHeadwords;
|
||||
headwords.clear();
|
||||
|
||||
try
|
||||
{
|
||||
getAllHeadwords( setOfHeadwords );
|
||||
|
||||
if( setOfHeadwords.size() )
|
||||
{
|
||||
headwords.reserve( setOfHeadwords.size() );
|
||||
|
||||
for( QSet< QString >::const_iterator it = setOfHeadwords.constBegin();
|
||||
it != setOfHeadwords.constEnd(); ++it )
|
||||
{
|
||||
headwords.append( *it );
|
||||
}
|
||||
|
||||
headwords.sort();
|
||||
}
|
||||
}
|
||||
catch( std::exception &ex )
|
||||
{
|
||||
gdWarning( "Failed headwords retrieving for \"%s\", reason: %s\n", getName().c_str(), ex.what() );
|
||||
}
|
||||
|
||||
return headwords.size() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
29
btreeidx.hh
29
btreeidx.hh
|
@ -10,6 +10,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdint_msvc.h>
|
||||
|
@ -55,6 +57,21 @@ struct WordArticleLink
|
|||
{}
|
||||
};
|
||||
|
||||
/// Links for full-text search
|
||||
struct FTSLink
|
||||
{
|
||||
string word; // in utf8
|
||||
uint32_t articleOffset;
|
||||
uint32_t linkOffset;
|
||||
|
||||
FTSLink()
|
||||
{}
|
||||
|
||||
FTSLink( string const & word_, uint32_t articleOffset_ ):
|
||||
word( word_ ), articleOffset( articleOffset_ ), linkOffset( 0 )
|
||||
{}
|
||||
};
|
||||
|
||||
/// Information needed to open the index
|
||||
struct IndexInfo
|
||||
{
|
||||
|
@ -83,6 +100,11 @@ public:
|
|||
/// is performed.
|
||||
vector< WordArticleLink > findArticles( wstring const & );
|
||||
|
||||
/// Find all chain offsets in the index
|
||||
void findAllArticleLinks( QVector< FTSLink > & articleLinks );
|
||||
|
||||
/// Retrieve all unique headwors from index
|
||||
void getAllHeadwords( QSet< QString > & headwords );
|
||||
protected:
|
||||
|
||||
/// Finds the offset in the btree leaf for the given word, either matching
|
||||
|
@ -115,6 +137,11 @@ protected:
|
|||
/// are left.
|
||||
void antialias( wstring const &, vector< WordArticleLink > & );
|
||||
|
||||
/// Find all article links for node
|
||||
void findNodeArticleLinks( uint32_t currentNodeOffset,
|
||||
QVector< FTSLink > * articleLinks,
|
||||
QSet< uint32_t > * offsets,
|
||||
QSet< QString > * headwords );
|
||||
protected:
|
||||
|
||||
Mutex * idxFileMutex;
|
||||
|
@ -158,6 +185,8 @@ public:
|
|||
virtual bool isLocalDictionary()
|
||||
{ return true; }
|
||||
|
||||
virtual bool getHeadwords( QStringList &headwords );
|
||||
|
||||
protected:
|
||||
|
||||
/// Called before each matching operation to ensure that any child init
|
||||
|
|
45
config.cc
45
config.cc
|
@ -870,6 +870,26 @@ Class load() throw( exError )
|
|||
}
|
||||
}
|
||||
|
||||
QDomNode headwordsDialog = root.namedItem( "headwordsDialog" );
|
||||
|
||||
if ( !headwordsDialog.isNull() )
|
||||
{
|
||||
if ( !headwordsDialog.namedItem( "searchMode" ).isNull() )
|
||||
c.headwordsDialog.searchMode = headwordsDialog.namedItem( "searchMode" ).toElement().text().toInt() ;
|
||||
|
||||
if ( !headwordsDialog.namedItem( "matchCase" ).isNull() )
|
||||
c.headwordsDialog.matchCase = ( headwordsDialog.namedItem( "matchCase" ).toElement().text() == "1" );
|
||||
|
||||
if ( !headwordsDialog.namedItem( "autoApply" ).isNull() )
|
||||
c.headwordsDialog.autoApply = ( headwordsDialog.namedItem( "autoApply" ).toElement().text() == "1" );
|
||||
|
||||
if ( !headwordsDialog.namedItem( "headwordsExportPath" ).isNull() )
|
||||
c.headwordsDialog.headwordsExportPath = headwordsDialog.namedItem( "headwordsExportPath" ).toElement().text();
|
||||
|
||||
if ( !headwordsDialog.namedItem( "headwordsDialogGeometry" ).isNull() )
|
||||
c.headwordsDialog.headwordsDialogGeometry = QByteArray::fromBase64( headwordsDialog.namedItem( "headwordsDialogGeometry" ).toElement().text().toLatin1() );
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -1646,6 +1666,31 @@ void save( Class const & c ) throw( exError )
|
|||
root.appendChild( opt );
|
||||
}
|
||||
|
||||
{
|
||||
QDomNode hd = dd.createElement( "headwordsDialog" );
|
||||
root.appendChild( hd );
|
||||
|
||||
QDomElement opt = dd.createElement( "searchMode" );
|
||||
opt.appendChild( dd.createTextNode( QString::number( c.headwordsDialog.searchMode ) ) );
|
||||
hd.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "matchCase" );
|
||||
opt.appendChild( dd.createTextNode( c.headwordsDialog.matchCase ? "1" : "0" ) );
|
||||
hd.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "autoApply" );
|
||||
opt.appendChild( dd.createTextNode( c.headwordsDialog.autoApply ? "1" : "0" ) );
|
||||
hd.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "headwordsExportPath" );
|
||||
opt.appendChild( dd.createTextNode( c.headwordsDialog.headwordsExportPath ) );
|
||||
hd.appendChild( opt );
|
||||
|
||||
opt = dd.createElement( "headwordsDialogGeometry" );
|
||||
opt.appendChild( dd.createTextNode( QString::fromLatin1( c.headwordsDialog.headwordsDialogGeometry.toBase64() ) ) );
|
||||
hd.appendChild( opt );
|
||||
}
|
||||
|
||||
QByteArray result( dd.toByteArray() );
|
||||
|
||||
if ( configFile.write( result ) != result.size() )
|
||||
|
|
16
config.hh
16
config.hh
|
@ -426,6 +426,20 @@ struct VoiceEngine
|
|||
|
||||
typedef QVector< VoiceEngine> VoiceEngines;
|
||||
|
||||
struct HeadwordsDialog
|
||||
{
|
||||
int searchMode;
|
||||
bool matchCase;
|
||||
bool autoApply;
|
||||
QString headwordsExportPath;
|
||||
QByteArray headwordsDialogGeometry;
|
||||
|
||||
HeadwordsDialog() :
|
||||
searchMode( 0 ), matchCase( false )
|
||||
, autoApply( false )
|
||||
{}
|
||||
};
|
||||
|
||||
struct Class
|
||||
{
|
||||
Paths paths;
|
||||
|
@ -476,6 +490,8 @@ struct Class
|
|||
/// Bigger headwords won't be indexed. For now, only in DSL.
|
||||
unsigned int maxHeadwordSize;
|
||||
|
||||
HeadwordsDialog headwordsDialog;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QRect maximizedMainWindowGeometry;
|
||||
QRect normalMainWindowGeometry;
|
||||
|
|
255
dictheadwords.cc
Normal file
255
dictheadwords.cc
Normal file
|
@ -0,0 +1,255 @@
|
|||
/* This file is (c) 2014 Abs62
|
||||
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
||||
|
||||
#include "dictheadwords.hh"
|
||||
#include "gddebug.hh"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QTimer>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#define AUTO_APPLY_LIMIT 150000
|
||||
|
||||
DictHeadwords::DictHeadwords( QWidget *parent, Config::Class & cfg_,
|
||||
Dictionary::Class * dict_ ) :
|
||||
QDialog(parent)
|
||||
, cfg( cfg_ )
|
||||
, dict( dict_ )
|
||||
{
|
||||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
ui.setupUi( this );
|
||||
|
||||
if( cfg.headwordsDialog.headwordsDialogGeometry.size() > 0 )
|
||||
restoreGeometry( cfg.headwordsDialog.headwordsDialogGeometry );
|
||||
|
||||
setWindowTitle( QString::fromUtf8( dict->getName().c_str() ) );
|
||||
|
||||
ui.searchModeCombo->addItem( tr( "Text" ), QRegExp::FixedString );
|
||||
ui.searchModeCombo->addItem( tr( "Wildcards" ), QRegExp::Wildcard );
|
||||
ui.searchModeCombo->addItem( tr( "RegExp" ), QRegExp::RegExp );
|
||||
ui.searchModeCombo->setCurrentIndex( cfg.headwordsDialog.searchMode );
|
||||
|
||||
ui.exportButton->setAutoDefault( false );
|
||||
ui.OKButton->setAutoDefault( false);
|
||||
ui.applyButton->setAutoDefault( true );
|
||||
ui.applyButton->setDefault( true );
|
||||
|
||||
ui.matchCase->setChecked( cfg.headwordsDialog.matchCase );
|
||||
|
||||
dict->getHeadwords( headers );
|
||||
|
||||
model = new QStringListModel( this );
|
||||
model->setStringList( headers );
|
||||
|
||||
proxy = new QSortFilterProxyModel( this );
|
||||
|
||||
proxy->setSourceModel( model );
|
||||
// proxy->setDynamicSortFilter( true );
|
||||
|
||||
ui.headersListView->setModel( proxy );
|
||||
|
||||
// very important call, for performance reasons:
|
||||
ui.headersListView->setUniformItemSizes( true );
|
||||
|
||||
delegate = new WordListItemDelegate( ui.headersListView->itemDelegate() );
|
||||
if( delegate )
|
||||
ui.headersListView->setItemDelegate( delegate );
|
||||
|
||||
if( headers.size() > AUTO_APPLY_LIMIT )
|
||||
{
|
||||
ui.autoApply->setChecked( false );
|
||||
ui.autoApply->setEnabled( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.autoApply->setChecked( cfg.headwordsDialog.autoApply );
|
||||
ui.applyButton->setEnabled( !cfg.headwordsDialog.autoApply );
|
||||
}
|
||||
|
||||
connect( this, SIGNAL( finished( int ) ), this, SLOT( savePos( int ) ) );
|
||||
|
||||
connect( ui.OKButton, SIGNAL( clicked( bool ) ), this, SLOT( okButtonClicked() ) );
|
||||
connect( ui.exportButton, SIGNAL( clicked( bool ) ), this, SLOT( exportButtonClicked() ) );
|
||||
connect( ui.applyButton, SIGNAL( clicked( bool ) ), this, SLOT( filterChanged() ) );
|
||||
|
||||
connect( ui.autoApply, SIGNAL( stateChanged( int ) ),
|
||||
this, SLOT( autoApplyStateChanged( int ) ) );
|
||||
|
||||
connect( ui.filterLine, SIGNAL( textChanged( QString ) ),
|
||||
this, SLOT( filterChangedInternal() ) );
|
||||
connect( ui.searchModeCombo, SIGNAL( currentIndexChanged( int ) ),
|
||||
this, SLOT( filterChangedInternal() ) );
|
||||
connect( ui.matchCase, SIGNAL( stateChanged( int ) ),
|
||||
this, SLOT( filterChangedInternal() ) );
|
||||
|
||||
connect( ui.headersListView, SIGNAL( clicked( QModelIndex ) ),
|
||||
this, SLOT( itemClicked( QModelIndex ) ) );
|
||||
|
||||
connect( proxy, SIGNAL( dataChanged( QModelIndex, QModelIndex ) ),
|
||||
this, SLOT( showHeadwordsNumber() ) );
|
||||
|
||||
showHeadwordsNumber();
|
||||
|
||||
QApplication::setOverrideCursor( Qt::ArrowCursor );
|
||||
}
|
||||
|
||||
DictHeadwords::~DictHeadwords()
|
||||
{
|
||||
if( delegate )
|
||||
delete delegate;
|
||||
}
|
||||
|
||||
void DictHeadwords::savePos( int )
|
||||
{
|
||||
cfg.headwordsDialog.searchMode = ui.searchModeCombo->currentIndex();
|
||||
cfg.headwordsDialog.matchCase = ui.matchCase->isChecked();
|
||||
|
||||
if( headers.size() <= AUTO_APPLY_LIMIT )
|
||||
cfg.headwordsDialog.autoApply = ui.autoApply->isChecked();
|
||||
|
||||
cfg.headwordsDialog.headwordsDialogGeometry = saveGeometry();
|
||||
}
|
||||
|
||||
void DictHeadwords::okButtonClicked()
|
||||
{
|
||||
done( 0 );
|
||||
}
|
||||
|
||||
void DictHeadwords::exportButtonClicked()
|
||||
{
|
||||
saveHeadersToFile();
|
||||
}
|
||||
|
||||
void DictHeadwords::filterChangedInternal()
|
||||
{
|
||||
// emit signal in async manner, to avoid UI slowdown
|
||||
if( ui.autoApply->isChecked() )
|
||||
QTimer::singleShot( 100, this, SLOT( filterChanged() ) );
|
||||
}
|
||||
|
||||
void DictHeadwords::filterChanged()
|
||||
{
|
||||
QRegExp::PatternSyntax syntax =
|
||||
QRegExp::PatternSyntax( ui.searchModeCombo->itemData(
|
||||
ui.searchModeCombo->currentIndex()).toInt() );
|
||||
|
||||
Qt::CaseSensitivity caseSensitivity = ui.matchCase->isChecked() ? Qt::CaseSensitive
|
||||
: Qt::CaseInsensitive;
|
||||
|
||||
QRegExp regExp( ui.filterLine->text(), caseSensitivity, syntax );
|
||||
|
||||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
proxy->setFilterRegExp( regExp );
|
||||
|
||||
QApplication::setOverrideCursor( Qt::ArrowCursor );
|
||||
|
||||
showHeadwordsNumber();
|
||||
}
|
||||
|
||||
void DictHeadwords::itemClicked( const QModelIndex & index )
|
||||
{
|
||||
QVariant value = proxy->data( index, Qt::DisplayRole );
|
||||
if ( value.canConvert< QString >() )
|
||||
emit headwordSelected( value.toString() );
|
||||
}
|
||||
|
||||
void DictHeadwords::autoApplyStateChanged( int state )
|
||||
{
|
||||
ui.applyButton->setEnabled( state == Qt::Unchecked );
|
||||
}
|
||||
|
||||
void DictHeadwords::showHeadwordsNumber()
|
||||
{
|
||||
ui.headersNumber->setText( tr( "Unique headwords total: %1, filtered: %2" )
|
||||
.arg( QString::number( headers.size() ) )
|
||||
.arg( QString::number( proxy->rowCount() ) ) );
|
||||
}
|
||||
|
||||
void DictHeadwords::saveHeadersToFile()
|
||||
{
|
||||
QString exportPath;
|
||||
if( cfg.headwordsDialog.headwordsExportPath.isEmpty() )
|
||||
exportPath = QDir::homePath();
|
||||
else
|
||||
{
|
||||
exportPath = QDir::fromNativeSeparators( cfg.headwordsDialog.headwordsExportPath );
|
||||
if( !QDir( exportPath ).exists() )
|
||||
exportPath = QDir::homePath();
|
||||
}
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName( this, tr( "Save headwords to file" ),
|
||||
exportPath,
|
||||
tr( "Text files (*.txt);;All files (*.*)" ) );
|
||||
if( fileName.size() == 0)
|
||||
return;
|
||||
|
||||
cfg.headwordsDialog.headwordsExportPath = QDir::toNativeSeparators(
|
||||
QFileInfo( fileName ).absoluteDir().absolutePath() );
|
||||
QFile file( fileName );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if ( !file.open( QFile::WriteOnly | QIODevice::Text ) )
|
||||
break;
|
||||
|
||||
int headwordsNumber = proxy->rowCount();
|
||||
|
||||
// Setup progress dialog
|
||||
int n = headwordsNumber;
|
||||
int step = 1;
|
||||
while( n > 1000 )
|
||||
{
|
||||
step *= 10;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
QProgressDialog progress( tr( "Export headwords..."), tr( "Cancel" ),
|
||||
0, n, this );
|
||||
progress.setWindowModality( Qt::WindowModal );
|
||||
|
||||
// Write UTF-8 BOM
|
||||
QByteArray line;
|
||||
line.append( 0xEF ).append( 0xBB ).append( 0xBF );
|
||||
if ( file.write( line ) != line.size() )
|
||||
break;
|
||||
|
||||
// Write headwords
|
||||
|
||||
int i;
|
||||
for( i = 0; i < headwordsNumber; ++i )
|
||||
{
|
||||
if( i % step == 0 )
|
||||
progress.setValue( i / step );
|
||||
|
||||
if( progress.wasCanceled() )
|
||||
break;
|
||||
|
||||
QVariant value = proxy->data( proxy->index( i, 0 ) );
|
||||
if( !value.canConvert< QString >() )
|
||||
continue;
|
||||
|
||||
line = value.toString().toUtf8();
|
||||
|
||||
line.replace( '\n', ' ' );
|
||||
line.replace( '\r', ' ' );
|
||||
|
||||
line += "\n";
|
||||
|
||||
if ( file.write( line ) != line.size() )
|
||||
break;
|
||||
}
|
||||
|
||||
if( i < headwordsNumber && !progress.wasCanceled() )
|
||||
break;
|
||||
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
|
||||
gdWarning( "Headers export error: %s", file.errorString().toUtf8().data() );
|
||||
file.close();
|
||||
}
|
53
dictheadwords.hh
Normal file
53
dictheadwords.hh
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef __DICTHEADWORDS_H_INCLUDED__
|
||||
#define __DICTHEADWORDS_H_INCLUDED__
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "config.hh"
|
||||
#include "ui_dictheadwords.h"
|
||||
#include "dictionary.hh"
|
||||
#include "delegate.hh"
|
||||
|
||||
class DictHeadwords : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DictHeadwords( QWidget * parent, Config::Class & cfg_,
|
||||
Dictionary::Class * dict_ );
|
||||
virtual ~DictHeadwords();
|
||||
|
||||
void setup();
|
||||
|
||||
protected:
|
||||
Config::Class & cfg;
|
||||
Dictionary::Class * dict;
|
||||
QStringList headers;
|
||||
QStringListModel * model;
|
||||
QSortFilterProxyModel * proxy;
|
||||
WordListItemDelegate * delegate;
|
||||
|
||||
void saveHeadersToFile();
|
||||
|
||||
private:
|
||||
Ui::DictHeadwords ui;
|
||||
private slots:
|
||||
void savePos( int );
|
||||
void filterChangedInternal();
|
||||
void filterChanged();
|
||||
void exportButtonClicked();
|
||||
void okButtonClicked();
|
||||
void itemClicked( const QModelIndex & index );
|
||||
void autoApplyStateChanged( int state );
|
||||
void showHeadwordsNumber();
|
||||
|
||||
signals:
|
||||
void headwordSelected( QString const & );
|
||||
};
|
||||
|
||||
#endif // __DICTHEADWORDS_H_INCLUDED__
|
141
dictheadwords.ui
Normal file
141
dictheadwords.ui
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DictHeadwords</class>
|
||||
<widget class="QDialog" name="DictHeadwords">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>458</width>
|
||||
<height>550</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="0">
|
||||
<widget class="QListView" name="headersListView"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Search mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="searchModeCombo">
|
||||
<property name="toolTip">
|
||||
<string>This element determines how filter string will be interpreted</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="matchCase">
|
||||
<property name="toolTip">
|
||||
<string>If checked on the symbols case will be take in account when filtering</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Match case</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="exportButton">
|
||||
<property name="toolTip">
|
||||
<string>Expors headwords to file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="OKButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="applyButton">
|
||||
<property name="toolTip">
|
||||
<string>Press this button to apply filter to headwords list</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="autoApply">
|
||||
<property name="toolTip">
|
||||
<string>If checked any filter changes will we immediately applied to headwords list</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filter:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLineEdit" name="filterLine">
|
||||
<property name="toolTip">
|
||||
<string>Filter string (fixed string, wildcards or regular expression)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="headersNumber">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
15
dictinfo.cc
15
dictinfo.cc
|
@ -28,6 +28,11 @@ void DictInfo::showInfo( sptr<Dictionary::Class> dict )
|
|||
ui.editDictionary->setToolTip(
|
||||
tr( "Edit the dictionary via command:\n%1" ).arg( cfg.editDictionaryCommandLine ) );
|
||||
|
||||
if( dict->getWordCount() == 0 )
|
||||
ui.headwordsButton->setVisible( false );
|
||||
else
|
||||
ui.buttonsLayout->insertSpacerItem( 0, new QSpacerItem( 40, 20, QSizePolicy::Expanding ) );
|
||||
|
||||
std::vector< std::string > const & filenames = dict->getDictionaryFilenames();
|
||||
|
||||
QString filenamesText;
|
||||
|
@ -62,3 +67,13 @@ void DictInfo::on_openFolder_clicked()
|
|||
{
|
||||
done( OPEN_FOLDER );
|
||||
}
|
||||
|
||||
void DictInfo::on_OKButton_clicked()
|
||||
{
|
||||
done( ACCEPTED );
|
||||
}
|
||||
|
||||
void DictInfo::on_headwordsButton_clicked()
|
||||
{
|
||||
done( SHOW_HEADWORDS );
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ public:
|
|||
REJECTED,
|
||||
ACCEPTED,
|
||||
OPEN_FOLDER,
|
||||
EDIT_DICTIONARY
|
||||
EDIT_DICTIONARY,
|
||||
SHOW_HEADWORDS
|
||||
};
|
||||
|
||||
DictInfo( Config::Class &cfg_, QWidget * parent = 0 );
|
||||
|
@ -29,6 +30,8 @@ private slots:
|
|||
void savePos( int );
|
||||
void on_editDictionary_clicked();
|
||||
void on_openFolder_clicked();
|
||||
void on_OKButton_clicked();
|
||||
void on_headwordsButton_clicked();
|
||||
};
|
||||
|
||||
#endif // DICTINFO_HH
|
||||
|
|
94
dictinfo.ui
94
dictinfo.ui
|
@ -256,50 +256,60 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="buttonsLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="headwordsButton">
|
||||
<property name="toolTip">
|
||||
<string>Show all unique dictionary headwords</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Headwords</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</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>
|
||||
<item>
|
||||
<widget class="QPushButton" name="OKButton">
|
||||
<property name="text">
|
||||
<string notr="true">OK</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<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>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DictInfo</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>180</x>
|
||||
<y>379</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>25</x>
|
||||
<y>791</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DictInfo</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>378</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>199</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <map>
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
#include <QStringList>
|
||||
#include "sptr.hh"
|
||||
#include "ex.hh"
|
||||
#include "mutex.hh"
|
||||
|
@ -400,6 +401,10 @@ public:
|
|||
virtual bool isLocalDictionary()
|
||||
{ return false; }
|
||||
|
||||
/// Retrieve all dictionary headwords
|
||||
virtual bool getHeadwords( QStringList & )
|
||||
{ return false; }
|
||||
|
||||
virtual ~Class()
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -281,7 +281,8 @@ HEADERS += folding.hh \
|
|||
zim.hh \
|
||||
gddebug.hh \
|
||||
gestures.hh \
|
||||
tiff.hh
|
||||
tiff.hh \
|
||||
dictheadwords.hh
|
||||
|
||||
FORMS += groups.ui \
|
||||
dictgroupwidget.ui \
|
||||
|
@ -295,7 +296,8 @@ FORMS += groups.ui \
|
|||
about.ui \
|
||||
editdictionaries.ui \
|
||||
orderandprops.ui \
|
||||
dictinfo.ui
|
||||
dictinfo.ui \
|
||||
dictheadwords.ui
|
||||
SOURCES += folding.cc \
|
||||
main.cc \
|
||||
dictionary.cc \
|
||||
|
@ -394,7 +396,8 @@ SOURCES += folding.cc \
|
|||
zim.cc \
|
||||
gddebug.cc \
|
||||
gestures.cc \
|
||||
tiff.cc
|
||||
tiff.cc \
|
||||
dictheadwords.cc
|
||||
|
||||
win32 {
|
||||
FORMS += texttospeechsource.ui
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "about.hh"
|
||||
#include "mruqmenu.hh"
|
||||
#include "gestures.hh"
|
||||
#include "dictheadwords.hh"
|
||||
#include <limits.h>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
|
@ -3556,6 +3557,15 @@ void MainWindow::showDictionaryInfo( const QString & id )
|
|||
{
|
||||
editDictionary( dictionaries[x].get() );
|
||||
}
|
||||
else if( result == DictInfo::SHOW_HEADWORDS )
|
||||
{
|
||||
DictHeadwords headwordsDlg( this, cfg, dictionaries[ x ].get() );
|
||||
|
||||
connect( &headwordsDlg, SIGNAL( headwordSelected( QString ) ),
|
||||
this, SLOT( wordReceived( QString ) ) );
|
||||
|
||||
headwordsDlg.exec();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue