+ 'WebSites' implemented.

*! Don't set a global qt stylesheet - sometimes WebKit crashes with it.
*! Fixes for text search feature (works faster, no selection artifacts, frame
   doesn't grow).
This commit is contained in:
Konstantin Isakov 2009-05-16 18:04:21 +00:00
parent 747825a505
commit 93fe5e5301
18 changed files with 1343 additions and 754 deletions

View file

@ -323,6 +323,14 @@ div.sdct_x
margin-top: 1em;
}
/************* Websites *****************/
.website_padding
{
height: 1em;
clear:both;
}
/************* MediaWiki articles *****************
The following consist of excerpts from different .css files edited
with a .mwiki prepended to each record.

View file

@ -174,6 +174,42 @@ void ArticleView::loadFinished( bool )
setCurrentArticle( url.fragment() );
}
// See if we have any iframes in need of expansion
QList< QWebFrame * > frames = ui.definition->page()->mainFrame()->childFrames();
bool wereFrames = false;
for( QList< QWebFrame * >::iterator i = frames.begin(); i != frames.end(); ++i )
{
if ( (*i)->frameName().startsWith( "gdexpandframe-" ) )
{
//printf( "Name: %s\n", (*i)->frameName().toUtf8().data() );
//printf( "Size: %d\n", (*i)->contentsSize().height() );
//printf( ">>>>>>>>Height = %s\n", (*i)->evaluateJavaScript( "document.body.offsetHeight;" ).toString().toUtf8().data() );
// Set the height
ui.definition->page()->mainFrame()->evaluateJavaScript( QString( "document.getElementById('%1').height = %2;" ).
arg( (*i)->frameName() ).
arg( (*i)->contentsSize().height() ) );
// Show it
ui.definition->page()->mainFrame()->evaluateJavaScript( QString( "document.getElementById('%1').style.display = 'block';" ).
arg( (*i)->frameName() ) );
wereFrames = true;
}
}
if ( wereFrames )
{
// There's some sort of glitch -- sometimes you need to move a mouse
QMouseEvent ev( QEvent::MouseMove, QPoint(), Qt::MouseButton(), 0, 0 );
qApp->sendEvent( ui.definition, &ev );
}
ui.definition->unsetCursor();
//QApplication::restoreOverrideCursor();
emit pageLoaded( this );
@ -218,14 +254,14 @@ unsigned ArticleView::getGroup( QUrl const & url )
QStringList ArticleView::getArticlesList()
{
return ui.definition->page()->currentFrame()->
return ui.definition->page()->mainFrame()->
evaluateJavaScript( "gdArticleContents;" ).toString().
trimmed().split( ' ', QString::SkipEmptyParts );
}
QString ArticleView::getCurrentArticle()
{
QVariant v = ui.definition->page()->currentFrame()->evaluateJavaScript(
QVariant v = ui.definition->page()->mainFrame()->evaluateJavaScript(
QString( "gdCurrentArticle;" ) );
if ( v.type() == QVariant::String )
@ -249,7 +285,7 @@ void ArticleView::setCurrentArticle( QString const & id, bool moveToIt )
}
ui.definition->history()->currentItem().setUserData( id );
ui.definition->page()->currentFrame()->evaluateJavaScript(
ui.definition->page()->mainFrame()->evaluateJavaScript(
QString( "gdMakeArticleActive( '%1' );" ).arg( id.mid( 7 ) ) );
}
}
@ -316,7 +352,7 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
{
if ( url.hasFragment() )
{
ui.definition->page()->currentFrame()->evaluateJavaScript(
ui.definition->page()->mainFrame()->evaluateJavaScript(
QString( "window.location = \"%1\"" ).arg( QString::fromUtf8( url.toEncoded() ) ) );
}
else
@ -440,13 +476,13 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
bool ArticleView::hasSound()
{
return ui.definition->page()->currentFrame()->
return ui.definition->page()->mainFrame()->
evaluateJavaScript( "gdAudioLink;" ).type() == QVariant::String;
}
void ArticleView::playSound()
{
QVariant v = ui.definition->page()->currentFrame()->evaluateJavaScript(
QVariant v = ui.definition->page()->mainFrame()->evaluateJavaScript(
QString( "gdAudioLink;" ) );
if ( v.type() == QVariant::String )
@ -455,12 +491,12 @@ void ArticleView::playSound()
QString ArticleView::toHtml()
{
return ui.definition->page()->currentFrame()->toHtml();
return ui.definition->page()->mainFrame()->toHtml();
}
QString ArticleView::getTitle()
{
return ui.definition->page()->currentFrame()->title();
return ui.definition->page()->mainFrame()->title();
}
void ArticleView::print( QPrinter * printer ) const
@ -472,7 +508,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
{
// Is that a link? Is there a selection?
QWebHitTestResult r = ui.definition->page()->currentFrame()->
QWebHitTestResult r = ui.definition->page()->mainFrame()->
hitTestContent( pos );
QMenu menu( this );
@ -803,14 +839,23 @@ void ArticleView::openSearch()
// Clear any current selection
if ( ui.definition->selectedText().size() )
{
ui.definition->triggerPageAction( QWebPage::SelectAll );
ui.definition->triggerPageAction( QWebPage::SelectStartOfDocument );
ui.definition->page()->currentFrame()->
evaluateJavaScript( "window.getSelection().removeAllRanges();" );
}
if ( ui.searchText->property( "noResults" ).toBool() )
{
ui.searchText->setProperty( "noResults", false );
qApp->setStyleSheet( qApp->styleSheet() );
// Reload stylesheet
for( QWidget * w = parentWidget(); w; w = w->parentWidget() )
{
if ( w->styleSheet().size() )
{
w->setStyleSheet( w->styleSheet() );
break;
}
}
}
}
@ -849,8 +894,8 @@ void ArticleView::performFindOperation( bool restart, bool backwards )
// For now we resort to this hack:
if ( ui.definition->selectedText().size() )
{
ui.definition->triggerPageAction( QWebPage::SelectAll );
ui.definition->triggerPageAction( QWebPage::SelectStartOfDocument );
ui.definition->page()->currentFrame()->
evaluateJavaScript( "window.getSelection().removeAllRanges();" );
}
}
@ -867,7 +912,16 @@ void ArticleView::performFindOperation( bool restart, bool backwards )
if ( ui.searchText->property( "noResults" ).toBool() != setMark )
{
ui.searchText->setProperty( "noResults", setMark );
qApp->setStyleSheet( qApp->styleSheet() );
// Reload stylesheet
for( QWidget * w = parentWidget(); w; w = w->parentWidget() )
{
if ( w->styleSheet().size() )
{
w->setStyleSheet( w->styleSheet() );
break;
}
}
}
}

View file

@ -13,7 +13,7 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="1000,0">
<property name="margin">
<number>0</number>
</property>
@ -43,6 +43,12 @@
</item>
<item>
<widget class="QFrame" name="searchFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>

View file

@ -126,6 +126,18 @@ MediaWikis makeDefaultMediaWikis( bool enable )
return mw;
}
WebSites makeDefaultWebSites()
{
WebSites ws;
ws.push_back( WebSite( "f376365a0de651fd7505e7e5e683aa45", "Urban Dictionary", "http://www.urbandictionary.com/define.php?term=%GDWORD%", false ) );
ws.push_back( WebSite( "324ca0306187df7511b26d3847f4b07c", "Multitran (En)", "http://multitran.ru/c/m.exe?CL=1&l1=1&s=%GD1251%", false ) );
ws.push_back( WebSite( "924db471b105299c82892067c0f10787", "Lingvo (En-Ru)", "http://www.abbyyonline.ru/translate.aspx?LingvoAction=translate&Ln=1&words=%GDWORD%", false ) );
ws.push_back( WebSite( "087a6d65615fb047f4c80eef0a9465db", "Michaelis (Pt-En)", "http://michaelis.uol.com.br/moderno/ingles/index.php?lingua=portugues-ingles&palavra=%GDISO1%", false ) );
return ws;
}
/// Sets option to true of false if node is "1" or "0" respectively, or leaves
/// it intact if it's neither "1" nor "0".
void applyBoolOption( bool & option, QDomNode const & node )
@ -225,6 +237,7 @@ Class load() throw( exError )
#endif
c.mediawikis = makeDefaultMediaWikis( true );
c.webSites = makeDefaultWebSites();
// Check if we have a template config file. If we do, load it instead
@ -392,6 +405,32 @@ Class load() throw( exError )
c.mediawikis = makeDefaultMediaWikis( false );
}
QDomNode wss = root.namedItem( "websites" );
if ( !wss.isNull() )
{
QDomNodeList nl = wss.toElement().elementsByTagName( "website" );
for( unsigned x = 0; x < nl.length(); ++x )
{
QDomElement ws = nl.item( x ).toElement();
WebSite w;
w.id = ws.attribute( "id" );
w.name = ws.attribute( "name" );
w.url = ws.attribute( "url" );
w.enabled = ( ws.attribute( "enabled" ) == "1" );
c.webSites.push_back( w );
}
}
else
{
// Upgrading
c.webSites = makeDefaultWebSites();
}
QDomNode preferences = root.namedItem( "preferences" );
if ( !preferences.isNull() )
@ -695,6 +734,33 @@ void save( Class const & c ) throw( exError )
}
}
{
QDomElement wss = dd.createElement( "websites" );
root.appendChild( wss );
for( WebSites::const_iterator i = c.webSites.begin(); i != c.webSites.end(); ++i )
{
QDomElement ws = dd.createElement( "website" );
wss.appendChild( ws );
QDomAttr id = dd.createAttribute( "id" );
id.setValue( i->id );
ws.setAttributeNode( id );
QDomAttr name = dd.createAttribute( "name" );
name.setValue( i->name );
ws.setAttributeNode( name );
QDomAttr url = dd.createAttribute( "url" );
url.setValue( i->url );
ws.setAttributeNode( url );
QDomAttr enabled = dd.createAttribute( "enabled" );
enabled.setValue( i->enabled ? "1" : "0" );
ws.setAttributeNode( enabled );
}
}
{
QDomElement preferences = dd.createElement( "preferences" );
root.appendChild( preferences );

View file

@ -180,6 +180,27 @@ struct MediaWiki
enabled == other.enabled; }
};
/// Any website which can be queried though a simple template substitution
struct WebSite
{
QString id, name, url;
bool enabled;
WebSite(): enabled( false )
{}
WebSite( QString const & id_, QString const & name_, QString const & url_,
bool enabled_ ):
id( id_ ), name( name_ ), url( url_ ), enabled( enabled_ ) {}
bool operator == ( WebSite const & other ) const
{ return id == other.id && name == other.name && url == other.url &&
enabled == other.enabled; }
};
/// All the WebSites
typedef vector< WebSite > WebSites;
/// Hunspell configuration
struct Hunspell
{
@ -256,6 +277,7 @@ struct Class
Groups groups;
Preferences preferences;
MediaWikis mediawikis;
WebSites webSites;
Hunspell hunspell;
Transliteration transliteration;

View file

@ -16,7 +16,7 @@ EditDictionaries::EditDictionaries( QWidget * parent, Config::Class & cfg_,
dictNetMgr( dictNetMgr_ ),
origCfg( cfg ),
sources( this, cfg.paths, cfg.soundDirs, cfg.hunspell, cfg.transliteration,
cfg.mediawikis ),
cfg.mediawikis, cfg.webSites ),
groups( new Groups( this, dictionaries, cfg.groups ) ),
dictionariesChanged( false ),
groupsChanged( false ),
@ -105,7 +105,8 @@ bool EditDictionaries::isSourcesChanged() const
sources.getSoundDirs() != cfg.soundDirs ||
sources.getHunspell() != cfg.hunspell ||
sources.getTransliteration() != cfg.transliteration ||
sources.getMediaWikis() != cfg.mediawikis;
sources.getMediaWikis() != cfg.mediawikis ||
sources.getWebSites() != cfg.webSites;
}
void EditDictionaries::acceptChangedSources( bool rebuildGroups )
@ -119,6 +120,7 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
cfg.hunspell = sources.getHunspell();
cfg.transliteration = sources.getTransliteration();
cfg.mediawikis = sources.getMediaWikis();
cfg.webSites = sources.getWebSites();
groupInstances.clear(); // Those hold pointers to dictionaries, we need to
// free them.

View file

@ -114,7 +114,8 @@ HEADERS += folding.hh \
transliteration.hh \
romaji.hh \
russiantranslit.hh \
german.hh
german.hh \
website.hh
FORMS += groups.ui \
dictgroupwidget.ui \
mainwindow.ui \
@ -179,7 +180,8 @@ SOURCES += folding.cc \
transliteration.cc \
romaji.cc \
russiantranslit.cc \
german.cc
german.cc \
website.cc
win32 {
SOURCES += mouseover_win32/ThTypes.c
HEADERS += mouseover_win32/ThTypes.h

BIN
src/icons/internet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -14,6 +14,7 @@
#include "romaji.hh"
#include "russiantranslit.hh"
#include "german.hh"
#include "website.hh"
#include <QMessageBox>
#include <QDir>
@ -191,6 +192,14 @@ void loadDictionaries( QWidget * parent, bool showInitially,
dictionaries.insert( dictionaries.end(), dicts.begin(), dicts.end() );
}
///// WebSites are very simple, no need to create them asyncronously
{
vector< sptr< Dictionary::Class > > dicts =
WebSite::makeDictionaries( cfg.webSites );
dictionaries.insert( dictionaries.end(), dicts.begin(), dicts.end() );
}
// Remove any stale index files
set< string > ids;

View file

@ -97,9 +97,6 @@ int main( int argc, char ** argv )
translator.load( QString( Config::getProgramDataDir() ) + "/locale/" + localeName );
app.installTranslator( &translator );
// Apply qt stylesheet
MainWindow::applyQtStyleSheet( cfg.preferences.displayStyle );
MainWindow m( cfg );
int r = app.exec();

View file

@ -39,6 +39,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
wordFinder( this ),
newReleaseCheckTimer( this )
{
applyQtStyleSheet( cfg.preferences.displayStyle );
ui.setupUi( this );
// Make the search pane's titlebar
@ -299,7 +301,7 @@ void MainWindow::applyQtStyleSheet( QString const & displayStyle )
if ( cssFile.open( QFile::ReadOnly ) )
css += cssFile.readAll();
qApp->setStyleSheet( css );
setStyleSheet( css );
}
void MainWindow::updateTrayIcon()
@ -458,6 +460,8 @@ void MainWindow::makeScanPopup()
scanPopup = new ScanPopup( 0, cfg, articleNetMgr, dictionaries, groupInstances );
scanPopup->setStyleSheet( styleSheet() );
if ( cfg.preferences.enableScanPopup && enableScanPopup->isChecked() )
scanPopup->enableScanning();
}
@ -719,7 +723,7 @@ void MainWindow::translateInputChanged( QString const & newValue )
if ( ui.translateLine->property( "noResults" ).toBool() )
{
ui.translateLine->setProperty( "noResults", false );
qApp->setStyleSheet( qApp->styleSheet() );
setStyleSheet( styleSheet() );
}
return;
}
@ -836,7 +840,7 @@ void MainWindow::updateMatchResults( bool finished )
if ( ui.translateLine->property( "noResults" ).toBool() != setMark )
{
ui.translateLine->setProperty( "noResults", setMark );
qApp->setStyleSheet( qApp->styleSheet() );
setStyleSheet( styleSheet() );
}
if ( !wordFinder.getErrorString().isEmpty() )

View file

@ -33,9 +33,6 @@ public:
MainWindow( Config::Class & cfg );
~MainWindow();
/// Applies the qt's stylesheet, given the style's name.
static void applyQtStyleSheet( QString const & displayStyle );
private:
QSystemTrayIcon * trayIcon;
@ -77,6 +74,9 @@ private:
QPrinter printer; // The printer we use for all printing operations
/// Applies the qt's stylesheet, given the style's name.
void applyQtStyleSheet( QString const & displayStyle );
/// Creates, destroys or otherwise updates tray icon, according to the
/// current configuration and situation.
void updateTrayIcon();

View file

@ -36,5 +36,6 @@
<file>icons/bookcase.png</file>
<file>qt-style-st-lingvo.css</file>
<file>article-style-st-lingvo.css</file>
<file>icons/internet.png</file>
</qresource>
</RCC>

View file

@ -11,8 +11,11 @@ Sources::Sources( QWidget * parent, Config::Paths const & paths,
Config::SoundDirs const & soundDirs,
Config::Hunspell const & hunspell,
Config::Transliteration const & tr,
Config::MediaWikis const & mediawikis ): QWidget( parent ),
mediawikisModel( this, mediawikis ), pathsModel( this, paths ),
Config::MediaWikis const & mediawikis,
Config::WebSites const & webSites ): QWidget( parent ),
mediawikisModel( this, mediawikis ),
webSitesModel( this, webSites ),
pathsModel( this, paths ),
soundDirsModel( this, soundDirs ),
hunspellDictsModel( this, hunspell )
{
@ -24,6 +27,12 @@ Sources::Sources( QWidget * parent, Config::Paths const & paths,
ui.mediaWikis->resizeColumnToContents( 1 );
ui.mediaWikis->resizeColumnToContents( 2 );
ui.webSites->setTabKeyNavigation( true );
ui.webSites->setModel( &webSitesModel );
ui.webSites->resizeColumnToContents( 0 );
ui.webSites->resizeColumnToContents( 1 );
ui.webSites->resizeColumnToContents( 2 );
ui.paths->setTabKeyNavigation( true );
ui.paths->setModel( &pathsModel );
@ -159,6 +168,30 @@ void Sources::on_removeMediaWiki_clicked()
mediawikisModel.removeWiki( current.row() );
}
void Sources::on_addWebSite_clicked()
{
webSitesModel.addNewSite();
QModelIndex result =
webSitesModel.index( webSitesModel.rowCount( QModelIndex() ) - 1,
1, QModelIndex() );
ui.webSites->scrollTo( result );
ui.webSites->edit( result );
}
void Sources::on_removeWebSite_clicked()
{
QModelIndex current = ui.webSites->currentIndex();
if ( current.isValid() &&
QMessageBox::question( this, tr( "Confirm removal" ),
tr( "Remove site <b>%1</b> from the list?" ).arg( webSitesModel.getCurrentWebSites()[ current.row() ].name ),
QMessageBox::Ok,
QMessageBox::Cancel ) == QMessageBox::Ok )
webSitesModel.removeSite( current.row() );
}
Config::Hunspell Sources::getHunspell() const
{
Config::Hunspell h;
@ -337,6 +370,160 @@ bool MediaWikisModel::setData( QModelIndex const & index, const QVariant & value
return false;
}
////////// WebSitesModel
WebSitesModel::WebSitesModel( QWidget * parent,
Config::WebSites const & webSites_ ):
QAbstractItemModel( parent ), webSites( webSites_ )
{
}
void WebSitesModel::removeSite( int index )
{
beginRemoveRows( QModelIndex(), index, index );
webSites.erase( webSites.begin() + index );
endRemoveRows();
}
void WebSitesModel::addNewSite()
{
Config::WebSite w;
w.enabled = false;
// That's quite some rng
w.id = QString(
QCryptographicHash::hash(
QDateTime::currentDateTime().toString( "\"WebSite\"dd.MM.yyyy hh:mm:ss.zzz" ).toUtf8(),
QCryptographicHash::Md5 ).toHex() );
w.url = "http://";
beginInsertRows( QModelIndex(), webSites.size(), webSites.size() );
webSites.push_back( w );
endInsertRows();
}
QModelIndex WebSitesModel::index( int row, int column, QModelIndex const & /*parent*/ ) const
{
return createIndex( row, column, 0 );
}
QModelIndex WebSitesModel::parent( QModelIndex const & /*parent*/ ) const
{
return QModelIndex();
}
Qt::ItemFlags WebSitesModel::flags( QModelIndex const & index ) const
{
Qt::ItemFlags result = QAbstractItemModel::flags( index );
if ( index.isValid() )
{
if ( !index.column() )
result |= Qt::ItemIsUserCheckable;
else
result |= Qt::ItemIsEditable;
}
return result;
}
int WebSitesModel::rowCount( QModelIndex const & parent ) const
{
if ( parent.isValid() )
return 0;
else
return webSites.size();
}
int WebSitesModel::columnCount( QModelIndex const & parent ) const
{
if ( parent.isValid() )
return 0;
else
return 3;
}
QVariant WebSitesModel::headerData( int section, Qt::Orientation /*orientation*/, int role ) const
{
if ( role == Qt::DisplayRole )
switch( section )
{
case 0:
return tr( "Enabled" );
case 1:
return tr( "Name" );
case 2:
return tr( "Address" );
default:
return QVariant();
}
return QVariant();
}
QVariant WebSitesModel::data( QModelIndex const & index, int role ) const
{
if ( (unsigned)index.row() >= webSites.size() )
return QVariant();
if ( role == Qt::DisplayRole || role == Qt::EditRole )
{
switch( index.column() )
{
case 1:
return webSites[ index.row() ].name;
case 2:
return webSites[ index.row() ].url;
default:
return QVariant();
}
}
if ( role == Qt::CheckStateRole && !index.column() )
return webSites[ index.row() ].enabled;
return QVariant();
}
bool WebSitesModel::setData( QModelIndex const & index, const QVariant & value,
int role )
{
if ( (unsigned)index.row() >= webSites.size() )
return false;
if ( role == Qt::CheckStateRole && !index.column() )
{
//printf( "type = %d\n", (int)value.type() );
//printf( "value = %d\n", (int)value.toInt() );
// XXX it seems to be always passing Int( 2 ) as a value, so we just toggle
webSites[ index.row() ].enabled = !webSites[ index.row() ].enabled;
dataChanged( index, index );
return true;
}
if ( role == Qt::DisplayRole || role == Qt::EditRole )
switch( index.column() )
{
case 1:
webSites[ index.row() ].name = value.toString();
dataChanged( index, index );
return true;
case 2:
webSites[ index.row() ].url = value.toString();
dataChanged( index, index );
return true;
default:
return false;
}
return false;
}
////////// PathsModel
PathsModel::PathsModel( QWidget * parent,

View file

@ -39,6 +39,36 @@ private:
Config::MediaWikis mediawikis;
};
/// A model to be projected into the webSites view, according to Qt's MVC model
class WebSitesModel: public QAbstractItemModel
{
Q_OBJECT
public:
WebSitesModel( QWidget * parent, Config::WebSites const & );
void removeSite( int index );
void addNewSite();
/// Returns the sites the model currently has listed
Config::WebSites const & getCurrentWebSites() const
{ return webSites; }
QModelIndex index( int row, int column, QModelIndex const & parent ) const;
QModelIndex parent( QModelIndex const & parent ) const;
Qt::ItemFlags flags( QModelIndex const & index ) const;
int rowCount( QModelIndex const & parent ) const;
int columnCount( QModelIndex const & parent ) const;
QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
QVariant data( QModelIndex const & index, int role ) const;
bool setData( QModelIndex const & index, const QVariant & value, int role );
private:
Config::WebSites webSites;
};
/// A model to be projected into the paths view, according to Qt's MVC model
class PathsModel: public QAbstractItemModel
{
@ -139,7 +169,8 @@ public:
Config::SoundDirs const &,
Config::Hunspell const &,
Config::Transliteration const &,
Config::MediaWikis const & );
Config::MediaWikis const &,
Config::WebSites const & );
Config::Paths const & getPaths() const
{ return pathsModel.getCurrentPaths(); }
@ -150,6 +181,9 @@ public:
Config::MediaWikis const & getMediaWikis() const
{ return mediawikisModel.getCurrentWikis(); }
Config::WebSites const & getWebSites() const
{ return webSitesModel.getCurrentWebSites(); }
Config::Hunspell getHunspell() const;
Config::Transliteration getTransliteration() const;
@ -162,6 +196,7 @@ signals:
private:
Ui::Sources ui;
MediaWikisModel mediawikisModel;
WebSitesModel webSitesModel;
PathsModel pathsModel;
SoundDirsModel soundDirsModel;
HunspellDictsModel hunspellDictsModel;
@ -183,6 +218,9 @@ private slots:
void on_addMediaWiki_clicked();
void on_removeMediaWiki_clicked();
void on_addWebSite_clicked();
void on_removeWebSite_clicked();
void on_rescan_clicked();
};

View file

@ -271,6 +271,69 @@ of the appropriate groups to use them.</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/internet.png</normaloff>:/icons/internet.png</iconset>
</attribute>
<attribute name="title">
<string>Websites</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Any websites. A string %GDWORD% will be replaced with the query word:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QTreeView" name="webSites"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QPushButton" name="addWebSite">
<property name="text">
<string>&amp;Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeWebSite">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Alternatively, use %GD1251% for CP1251, %GDISO1% for ISO 8859-1.</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Transliteration</string>

109
src/website.cc Normal file
View file

@ -0,0 +1,109 @@
/* 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 "website.hh"
#include "wstring_qt.hh"
#include <QUrl>
#include <QTextCodec>
namespace WebSite {
using namespace Dictionary;
namespace {
class WebSiteDictionary: public Dictionary::Class
{
string name;
QByteArray urlTemplate;
public:
WebSiteDictionary( string const & id, string const & name_,
QString const & urlTemplate_ ):
Dictionary::Class( id, vector< string >() ),
name( name_ ),
urlTemplate( QUrl( urlTemplate_ ).toEncoded() )
{
}
virtual string getName() throw()
{ return name; }
virtual map< Property, string > getProperties() throw()
{ return map< Property, string >(); }
virtual unsigned long getArticleCount() throw()
{ return 0; }
virtual unsigned long getWordCount() throw()
{ return 0; }
virtual QIcon getIcon() throw()
{ return QIcon(":/icons/internet.png"); }
virtual sptr< WordSearchRequest > prefixMatch( wstring const & word,
unsigned long ) throw( std::exception );
virtual sptr< DataRequest > getArticle( wstring const &, vector< wstring > const & alts )
throw( std::exception );
};
sptr< WordSearchRequest > WebSiteDictionary::prefixMatch( wstring const & word,
unsigned long ) throw( std::exception )
{
sptr< WordSearchRequestInstant > sr = new WordSearchRequestInstant;
sr->getMatches().push_back( WordMatch( word, 1 ) );
return sr;
}
sptr< DataRequest > WebSiteDictionary::getArticle( wstring const & str, vector< wstring > const & )
throw( std::exception )
{
sptr< DataRequestInstant > dr = new DataRequestInstant( true );
QByteArray urlString( urlTemplate );
QString inputWord = gd::toQString( str );
urlString.replace( "%25GDWORD%25", inputWord.toUtf8().toPercentEncoding() );
urlString.replace( "%25GD1251%25", QTextCodec::codecForName( "Windows-1251" )->fromUnicode( inputWord ).toPercentEncoding() );
urlString.replace( "%25GDISO1%25", QTextCodec::codecForName( "ISO 8859-1" )->fromUnicode( inputWord ).toPercentEncoding() );
string result = "<div class=\"website_padding\"></div>";
result += string( "<iframe id=\"gdexpandframe-" ) + getId() +
"\" src=\"" + urlString.data() +
"\" scrolling=\"no\" marginwidth=\"0\" marginheight=\"0\" "
"frameborder=\"0\" vspace=\"0\" hspace=\"0\" "
"style=\"overflow:visible; width:100%; display:none;\">"
"</iframe>";
dr->getData().resize( result.size() );
memcpy( &( dr->getData().front() ), result.data(), result.size() );
return dr;
}
}
vector< sptr< Dictionary::Class > > makeDictionaries( Config::WebSites const & ws )
throw( std::exception )
{
vector< sptr< Dictionary::Class > > result;
for( unsigned x = 0; x < ws.size(); ++x )
{
if ( ws[ x ].enabled )
result.push_back( new WebSiteDictionary( ws[ x ].id.toUtf8().data(),
ws[ x ].name.toUtf8().data(),
ws[ x ].url ) );
}
return result;
}
}

21
src/website.hh Normal file
View file

@ -0,0 +1,21 @@
/* 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 __WEBSITE_HH_INCLUDED__
#define __WEBSITE_HH_INCLUDED__
#include "dictionary.hh"
#include "config.hh"
/// Support for any web sites via a templated url.
namespace WebSite {
using std::vector;
using std::string;
vector< sptr< Dictionary::Class > > makeDictionaries( Config::WebSites const & )
throw( std::exception );
}
#endif