Allow to collapse/expand articles; auto collapse for big articles (issue #331)

This commit is contained in:
Abs62 2013-06-02 15:20:33 +04:00
parent 4a9d65232d
commit d721e627b1
11 changed files with 177 additions and 14 deletions

View file

@ -2713,3 +2713,19 @@ in bg url to hide it from iemac */
.mwiki .infl-table { display: none }
/****default hide dict icon ***/
.gddicticon{display:none;}
.gdexpandicon {
cursor:pointer;
width:16px;
height:16px;
vertical-align: text-bottom;
background-image:url('qrcx://localhost/icons/arrow.png');
}
.gdcollapseicon {
cursor:pointer;
width:16px;
height:16px;
vertical-align: text-bottom;
background-image:url('qrcx://localhost/icons/downarrow.png');
}

View file

@ -9,6 +9,7 @@
#include <limits.h>
#include <QFile>
#include <QUrl>
#include <QTextDocumentFragment>
#include "folding.hh"
#include "langcoder.hh"
#include "dprintf.hh"
@ -28,6 +29,8 @@ ArticleMaker::ArticleMaker( vector< sptr< Dictionary::Class > > const & dictiona
displayStyle( displayStyle_ ),
addonStyle( addonStyle_ ),
needExpandOptionalParts( true )
, collapseBigArticles( true )
, articleLimitSize( 500 )
{
}
@ -121,8 +124,8 @@ std::string ArticleMaker::makeHtmlHeader( QString const & word,
"gdAudioLinks = { first: null, current: null };"
"function gdMakeArticleActive( newId ) {"
"if ( gdCurrentArticle != 'gdfrom-' + newId ) {"
"document.getElementById( gdCurrentArticle ).className = 'gdarticle';"
"document.getElementById( 'gdfrom-' + newId ).className = 'gdarticle gdactivearticle';"
"el=document.getElementById( gdCurrentArticle ); el.className = el.className.replace(' gdactivearticle','');"
"el=document.getElementById( 'gdfrom-' + newId ); el.className = el.className + ' gdactivearticle';"
"gdCurrentArticle = 'gdfrom-' + newId; gdAudioLinks.current = newId;"
"articleview.onJsActiveArticleChanged(gdCurrentArticle); } }"
"var overIframeId = null;"
@ -137,7 +140,22 @@ std::string ArticleMaker::makeHtmlHeader( QString const & word,
"window.addEventListener('load', init, false);"
"function gdExpandOptPart( expanderId, optionalId ) { var d1=document.getElementById(expanderId); var i = 0; if( d1.alt == '[+]' ) {"
"d1.alt = '[-]'; d1.src = 'qrcx://localhost/icons/collapse_opt.png'; for( i = 0; i < 1000; i++ ) { var d2=document.getElementById( optionalId + i ); if( !d2 ) break; d2.style.display='inline'; } }"
"else { d1.alt = '[+]'; d1.src = 'qrcx://localhost/icons/expand_opt.png'; for( i = 0; i < 1000; i++ ) { var d2=document.getElementById( optionalId + i ); if( !d2 ) break; d2.style.display='none'; } } }"
"else { d1.alt = '[+]'; d1.src = 'qrcx://localhost/icons/expand_opt.png'; for( i = 0; i < 1000; i++ ) { var d2=document.getElementById( optionalId + i ); if( !d2 ) break; d2.style.display='none'; } } };"
"function gdExpandArticle( id ) { elem = document.getElementById('gdarticlefrom-'+id); ico = document.getElementById('expandicon-'+id); art=document.getElementById('gdfrom-'+id);"
"t=window.event.target || window.event.srcElement;"
"if(elem.style.display=='inline' && t==ico) {"
"elem.style.display='none'; ico.className='gdexpandicon';"
"art.className = art.className+' gdcollapsedarticle';"
"nm=document.getElementById('gddictname-'+id); nm.style.cursor='pointer';"
"window.event.stopPropagation(); ico.title=''; nm.title='";
result += tr( "Expand article" ).toUtf8().data();
result += "' } else {"
"elem.style.display='inline'; ico.className='gdcollapseicon';"
"art.className=art.className.replace(' gdcollapsedarticle','');"
"nm=document.getElementById('gddictname-'+id); nm.style.cursor='default';"
"nm.title=''; ico.title='";
result += tr( "Collapse article").toUtf8().data();
result += "' } }"
"</script>";
result += "</head><body>";
@ -259,11 +277,13 @@ sptr< Dictionary::DataRequest > ArticleMaker::makeDefinitionFor(
unmutedDicts.push_back( activeDicts[ x ] );
return new ArticleRequest( inWord.trimmed(), activeGroup ? activeGroup->name : "",
contexts, unmutedDicts, header );
contexts, unmutedDicts, header,
collapseBigArticles ? articleLimitSize : -1 );
}
else
return new ArticleRequest( inWord.trimmed(), activeGroup ? activeGroup->name : "",
contexts, activeDicts, header );
contexts, activeDicts, header,
collapseBigArticles ? articleLimitSize : -1 );
}
sptr< Dictionary::DataRequest > ArticleMaker::makeNotFoundTextFor(
@ -315,6 +335,13 @@ void ArticleMaker::setExpandOptionalParts( bool expand )
needExpandOptionalParts = expand;
}
void ArticleMaker::setCollapseParameters( bool autoCollapse, int articleSize )
{
collapseBigArticles = autoCollapse;
articleLimitSize = articleSize;
}
bool ArticleMaker::adjustFilePath( QString & fileName )
{
QFileInfo info( fileName );
@ -338,11 +365,13 @@ ArticleRequest::ArticleRequest(
QString const & word_, QString const & group_,
QMap< QString, QString > const & contexts_,
vector< sptr< Dictionary::Class > > const & activeDicts_,
string const & header ):
string const & header,
int sizeLimit ):
word( word_ ), group( group_ ), contexts( contexts_ ),
activeDicts( activeDicts_ ),
altsDone( false ), bodyDone( false ), foundAnyDefinitions( false ),
closePrevSpan( false )
, articleSizeLimit( sizeLimit )
{
// No need to lock dataMutex on construction
@ -461,7 +490,7 @@ void ArticleRequest::bodyFinished()
if ( closePrevSpan )
{
head += "</span></span><span class=\"gdarticleseparator\"></span>";
head += "</span></span><div style=\"clear:both;\"></div><span class=\"gdarticleseparator\"></span>";
}
else
{
@ -471,6 +500,22 @@ void ArticleRequest::bodyFinished()
"articleview.onJsActiveArticleChanged(gdCurrentArticle)</script>";
}
bool collapse = false;
if( articleSizeLimit >= 0 )
{
try
{
Mutex::Lock _( dataMutex );
QString text = QString::fromUtf8( req.getFullData().data(), req.getFullData().size() );
int size = QTextDocumentFragment::fromHtml( text ).toPlainText().length();
if( size > articleSizeLimit )
collapse = true;
}
catch(...)
{
}
}
string jsVal = Html::escapeForJavaScript( dictId );
head += "<script type=\"text/javascript\">var gdArticleContents; "
"if ( !gdArticleContents ) gdArticleContents = \"" + jsVal +" \"; "
@ -478,6 +523,7 @@ void ArticleRequest::bodyFinished()
head += string( "<span class=\"gdarticle" ) +
( closePrevSpan ? "" : " gdactivearticle" ) +
( collapse ? " gdcollapsedarticle" : "" ) +
"\" id=\"" + gdFrom +
"\" onClick=\"gdMakeArticleActive( '" + jsVal + "' );\" " +
" onContextMenu=\"gdMakeArticleActive( '" + jsVal + "' );\""
@ -485,18 +531,28 @@ void ArticleRequest::bodyFinished()
closePrevSpan = true;
head += string( "<div class=\"gddictname\"><span class=\"gddicticon\"><img src=\"gico://")
+ Html::escape( dictId )
head += string( "<div class=\"gddictname\" onclick=\"gdExpandArticle(\'" ) + dictId + "\');"
+ ( collapse ? "\" style=\"cursor:pointer;" : "" )
+ "\" id=\"gddictname-" + Html::escape( dictId ) + "\""
+ ( collapse ? string( " title=\"" ) + tr( "Expand article" ).toUtf8().data() + "\"" : "" )
+ "><span class=\"gddicticon\"><img src=\"gico://" + Html::escape( dictId )
+ "/dicticon.png\"></span><span class=\"gdfromprefix\">" +
Html::escape( tr( "From " ).toUtf8().data() ) + "</span>" +
Html::escape( activeDict->getName().c_str() )
+ "</div>";
+ "<span><img src=\"qrcx://localhost/icons/blank.png\" class=\""
+ ( collapse ? "gdexpandicon" : "gdcollapseicon" )
+ "\" id=\"expandicon-" + Html::escape( dictId ) + "\""
+ ( collapse ? "" : string( " title=\"" ) + tr( "Collapse article" ).toUtf8().data() + "\"" )
+ "></span>" + "</div>";
head += "<span class=\"gdarticlebody gdlangfrom-";
head += LangCoder::intToCode2( activeDict->getLangFrom() ).toLatin1().data();
head += "\" lang=\"";
head += LangCoder::intToCode2( activeDict->getLangTo() ).toLatin1().data();
head += "\">";
head += "\"";
head += " style=\"display:";
head += collapse ? "none" : "inline";
head += string( "\" id=\"gdarticlefrom-" ) + Html::escape( dictId ) + "\">";
if ( errorString.size() )
{

View file

@ -23,6 +23,8 @@ class ArticleMaker: public QObject
QString displayStyle, addonStyle;
bool needExpandOptionalParts;
bool collapseBigArticles;
int articleLimitSize;
public:
@ -71,6 +73,9 @@ public:
/// Return true if path successfully adjusted
static bool adjustFilePath( QString & fileName );
/// Set collapse articles parameters
void setCollapseParameters( bool autoCollapse, int articleSize );
private:
/// Makes everything up to and including the opening body tag.
@ -115,13 +120,15 @@ class ArticleRequest: public Dictionary::DataRequest
QString currentSplittedWordCompound;
QString lastGoodCompoundResult;
bool firstCompoundWasFound;
int articleSizeLimit;
public:
ArticleRequest( QString const & word, QString const & group,
QMap< QString, QString > const & contexts,
std::vector< sptr< Dictionary::Class > > const & activeDicts,
std::string const & header );
std::string const & header,
int sizeLimit );
virtual void cancel();
// { finish(); } // Add our own requests cancellation here

View file

@ -122,6 +122,8 @@ Preferences::Preferences():
storeHistory( 1 ),
alwaysExpandOptionalParts( true )
, historyStoreInterval( 0 )
, collapseBigArticles( false )
, articleSizeLimit( 2000 )
{
}
@ -725,6 +727,12 @@ Class load() throw( exError )
if ( !preferences.namedItem( "historyStoreInterval" ).isNull() )
c.preferences.historyStoreInterval = preferences.namedItem( "historyStoreInterval" ).toElement().text().toUInt() ;
if ( !preferences.namedItem( "collapseBigArticles" ).isNull() )
c.preferences.collapseBigArticles = ( preferences.namedItem( "collapseBigArticles" ).toElement().text() == "1" );
if ( !preferences.namedItem( "articleSizeLimit" ).isNull() )
c.preferences.articleSizeLimit = preferences.namedItem( "articleSizeLimit" ).toElement().text().toUInt() ;
}
c.lastMainGroupId = root.namedItem( "lastMainGroupId" ).toElement().text().toUInt();
@ -1446,7 +1454,14 @@ void save( Class const & c ) throw( exError )
opt = dd.createElement( "addonStyle" );
opt.appendChild( dd.createTextNode( c.preferences.addonStyle ) );
preferences.appendChild( opt );
}
opt = dd.createElement( "collapseBigArticles" );
opt.appendChild( dd.createTextNode( c.preferences.collapseBigArticles ? "1" : "0" ) );
preferences.appendChild( opt );
opt = dd.createElement( "articleSizeLimit" );
opt.appendChild( dd.createTextNode( QString::number( c.preferences.articleSizeLimit ) ) );
preferences.appendChild( opt ); }
{
QDomElement opt = dd.createElement( "lastMainGroupId" );

View file

@ -207,6 +207,9 @@ struct Preferences
unsigned historyStoreInterval;
bool collapseBigArticles;
int articleSizeLimit;
QString addonStyle;
Preferences();

BIN
icons/blank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
icons/downarrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

View file

@ -87,6 +87,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
ui.setupUi( this );
articleMaker.setCollapseParameters( cfg.preferences.collapseBigArticles, cfg.preferences.articleSizeLimit );
// use our own, cutsom statusbar
setStatusBar(0);
mainStatusBar = new MainStatusBar( this );
@ -1741,6 +1743,12 @@ void MainWindow::editPreferences()
needReload = true;
}
if( cfg.preferences.collapseBigArticles != p.collapseBigArticles
|| cfg.preferences.articleSizeLimit != p.articleSizeLimit )
{
articleMaker.setCollapseParameters( p.collapseBigArticles, p.articleSizeLimit );
}
// See if we need to reapply expand optional parts mode
if( cfg.preferences.alwaysExpandOptionalParts != p.alwaysExpandOptionalParts )
{

View file

@ -135,6 +135,9 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ):
ui.historySaveIntervalField->setValue( p.historyStoreInterval );
ui.alwaysExpandOptionalParts->setChecked( p.alwaysExpandOptionalParts );
ui.collapseBigArticles->setChecked( p.collapseBigArticles );
ui.articleSizeLimit->setValue( p.articleSizeLimit );
// Different platforms have different keys available
#ifdef Q_OS_WIN32
@ -252,6 +255,9 @@ Config::Preferences Preferences::getPreferences()
p.historyStoreInterval = ui.historySaveIntervalField->text().toUInt();
p.alwaysExpandOptionalParts = ui.alwaysExpandOptionalParts->isChecked();
p.collapseBigArticles = ui.collapseBigArticles->isChecked();
p.articleSizeLimit = ui.articleSizeLimit->text().toInt();
p.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked();
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();
p.useExternalPlayer = ui.useExternalPlayer->isChecked();

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>572</width>
<height>394</height>
<height>403</height>
</rect>
</property>
<property name="windowTitle">
@ -1231,6 +1231,56 @@ It is not needed to select this option if you don't use such programs.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QCheckBox" name="collapseBigArticles">
<property name="toolTip">
<string>Select this option to automatic collapse big articles</string>
</property>
<property name="text">
<string>Collapse articles more than</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="articleSizeLimit">
<property name="toolTip">
<string>Artiles longer than this size will be collapsed</string>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>50</number>
</property>
<property name="value">
<number>2000</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>symbols</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_11">
<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>
</item>

View file

@ -65,5 +65,7 @@
<file>qt-style-st-lingoes-blue.css</file>
<file>qt-style-macos.css</file>
<file>icons/mdict.png</file>
<file>icons/downarrow.png</file>
<file>icons/blank.png</file>
</qresource>
</RCC>