/* Marcion
Copyright (C) 2009 - 2011 Milan Konvicka
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program */
#include "booktextbrowser.h"
CBookTextBrowser::CBookTextBrowser(QWidget *parent) :
QWidget(parent),
bt_action(false),is_finalized(false),
//prg(false),
popup("menu"),messages(0),lasturl(),
orig_text(0)
{
setupUi(this);
connect(txtFind,SIGNAL(textChanged(QString const&)),this,SLOT(slot_input_textChanged(QString const &)));
s_crum=popup.addAction(tr("search Crum"));
s_lsj=popup.addAction(tr("search LSJ"));
searchlib=popup.addAction(tr("search in library"));
popup.addSeparator();
(copy=popup.addAction(tr("copy")))->setShortcut(QKeySequence("Ctrl+C"));
copyall=popup.addAction(tr("copy all"));
popup.addSeparator();
(find=popup.addAction(tr("show/hide panel")))->setShortcut(QKeySequence("Ctrl+P"));
find->setCheckable(true);
(show_inf=popup.addAction(tr("show/hide info")))->setCheckable(true);
popup.addSeparator();
(inc_font=popup.addAction(tr("larger font")))->setShortcut(QKeySequence("Ctrl+O"));
(dec_font=popup.addAction(tr("smaller font")))->setShortcut(QKeySequence("Ctrl+L"));
popup.addSeparator();
show_html=popup.addAction(tr("show html"));
//show_inf->setChecked(true);
cbWrap->setChecked(!(br->wordWrapMode()==QTextOption::NoWrap));
on_btHide_clicked();
}
CBookTextBrowser::~CBookTextBrowser()
{
deleteOrigText();
}
void CBookTextBrowser::find_greek_word(QString const & word)
{
emit dictionaryRequested(LSJ,word);
}
void CBookTextBrowser::find_word(QString const & word)
{
emit dictionaryRequested(Crum,word);
}
void CBookTextBrowser::searchLibrary(QString const & text)
{
messages->libSearchWidget().searchCoptic(text);
}
void CBookTextBrowser::init(
CMessages * const messages,
QString const & ,
Script script,
bool change_font
)
{
CMessages ** m=(CMessages**)&this->messages;
*m=messages;
CBookTextBrowser::script=script;
txtFind->setScript((CTranslit::Script)script);
cbAllowFont->setChecked(change_font);
QFont f(messages->settings().bFont((CTranslit::Script)script));
setFont(f);
}
void CBookTextBrowser::on_br_customContextMenuRequested(QPoint pos)
{
bool
sel=br->textCursor().hasSelection(),
fnt=cbAllowFont->isChecked();
s_crum->setEnabled(sel);
s_lsj->setEnabled(sel);
searchlib->setEnabled(sel);
copy->setEnabled(sel);
inc_font->setEnabled(fnt);
dec_font->setEnabled(fnt);
show_inf->setChecked(wdgInfo->isVisible());
find->setChecked(widget->isVisible());
QAction * a;
if((a=popup.exec(bt_action?pos:QCursor::pos())))
{
QString st(br->textCursor().selectedText());
if(a==s_crum)
{
if(!st.isEmpty())
find_word(st);
}
else if(a==s_lsj)
{
if(!st.isEmpty())
find_greek_word(st);
}
else if(a==copy)
{
br->copy();
}
else if(a==copyall)
{
QTextCursor tc(br->document());
tc.select(QTextCursor::Document);
QApplication::clipboard()->setText(tc.selectedText());
}
else if(a==find)
{
widget->setVisible(!widget->isVisible());
//tabOpts->setCurrentIndex(0);
}
else if(a==inc_font)
{
spnFSize->setValue(spnFSize->value()+1);
}
else if(a==dec_font)
{
spnFSize->setValue(spnFSize->value()-1);
}
else if(a==show_html)
{
br->setPlainText(br->toHtml());
}
else if(a==searchlib)
{
if(!st.isEmpty())
searchLibrary(st);
}
else if(a==show_inf)
{
wdgInfo->setVisible(show_inf->isChecked());
}
}
bt_action=false;
}
void CBookTextBrowser::on_btFind_clicked()
{
QString ft(txtFind->text_utf8());
if(ft.isEmpty())
return;
//USE_CLEAN_WAIT
QRegExp rft(ft,Qt::CaseInsensitive);
rft.setMinimal(true);
bool reg(cmbType->currentIndex()==1),wrds(cbWordsOnly->isChecked());
if(wrds)
{
USE_CLEAN_WAIT
CProgressDialog pd;
QTime time;
time.start();
bool prg(false);
QTextCursor tc(br->textCursor());
QTextDocument * newtd(br->document());
bool catched(false);
if(tc.hasSelection())
tc.movePosition(QTextCursor::NextWord,QTextCursor::MoveAnchor,1);
do
{
PRGD("detecting occurrence ...")
QTextCursor snc(tc);
snc.select(QTextCursor::WordUnderCursor);
QString st(snc.selectedText());
if(reg)
{
if(rft.indexIn(st)!=-1)
{
//fnc=fnc.document()->find(rft,nc);
catched=true;
break;
}
}
else
{
if(st.contains(ft,Qt::CaseInsensitive))
{
//fnc=fnc.document()->find(ft,nc);
catched=true;
break;
}
}
}while(tc.movePosition(QTextCursor::NextWord,QTextCursor::MoveAnchor,1));
if(!catched)
br->moveCursor(QTextCursor::End);
else
{
if(tc.isNull())
br->moveCursor(QTextCursor::End);
else
{
tc.select(QTextCursor::WordUnderCursor);
br->setTextCursor(tc);
}
}
/*QTextCursor nc;
if(reg)
nc=br->document()->find(rft,br->textCursor(),QTextDocument::FindWholeWords);
else
nc=br->document()->find(ft,br->textCursor(),QTextDocument::FindWholeWords);
if(nc.isNull())
br->moveCursor(QTextCursor::End);
else
br->setTextCursor(nc);*/
}
else
{
QTextCursor nc;
if(reg)
nc=br->document()->find(rft,br->textCursor());
else
nc=br->document()->find(ft,br->textCursor());
if(nc.isNull())
br->moveCursor(QTextCursor::End);
else
br->setTextCursor(nc);
}
}
void CBookTextBrowser::on_btHide_clicked()
{
widget->setVisible(false);
}
void CBookTextBrowser::on_cmbF_currentFontChanged(QFont f)
{
if(cbAllowFont->isChecked())
{
QFont nf(f);
nf.setPointSize(spnFSize->value());
br->setFont(nf);
}
}
void CBookTextBrowser::on_spnFSize_valueChanged(int newvalue)
{
if(cbAllowFont->isChecked())
{
QFont nf(cmbF->currentFont());
nf.setPointSize(newvalue);
br->setFont(nf);
}
}
void CBookTextBrowser::on_btTop_clicked()
{
br->moveCursor(QTextCursor::Start);
}
void CBookTextBrowser::slot_input_textChanged(QString const &)
{
//btHLText->setChecked(false);
//br->moveCursor(QTextCursor::PreviousWord);
//br->find(str);
QTime time;
time.start();
on_btTop_clicked();
on_btFind_clicked();
if(time.elapsed()>2000&&cbWordsOnly->isChecked())
{
messages->MsgInf("Document is too large, 'words' option disabled.");
cbWordsOnly->setChecked(false);
}
}
void CBookTextBrowser::on_cbRmAccents_clicked(bool checked)
{
bool processed=false;
emit contentChanged(checked, cbRmSpaces->isChecked(),&processed);
if(!processed)
highlight();
}
void CBookTextBrowser::on_cbRmSpaces_clicked(bool checked)
{
bool processed=false;
emit contentChanged(cbRmAccents->isChecked(), checked, &processed);
if(!processed)
highlight();
}
bool CBookTextBrowser::rmAccents() const
{
return cbRmAccents->isChecked();
}
bool CBookTextBrowser::rmSpaces() const
{
return cbRmSpaces->isChecked();
}
bool CBookTextBrowser::isHighlightChecked() const
{
return btHLText->isChecked();
}
void CBookTextBrowser::on_btHLText_clicked(bool )
{
highlight();
}
bool CBookTextBrowser::highlight()
{
USE_CLEAN_WAIT
setOrigText();
restoreOrigText();
//messages->MsgMsg("HL activated");
QTextDocument * newtd(br->document()->clone());
QTextCursor tc(newtd);
if(newtd)
{
CProgressDialog pd;
bool prg(false);
QTime time;
time.start();
if(rmAccents()&&!is_finalized)
{
tc.movePosition(QTextCursor::Start);
do
{
PRGD("removing non-word chars ...")
tc.select(QTextCursor::WordUnderCursor);
QString wrd(tc.selectedText());
if(CTranslit::isGreek(wrd))
{
wrd=CTranslit::tr(wrd,CTranslit::GreekNToGreekTr,true,false);
wrd=CTranslit::tr(wrd,CTranslit::GreekTrToGreekN,false,false);
}
else if(CTranslit::isCoptic(wrd))
{
wrd=CTranslit::tr(wrd,CTranslit::CopticNToCopticTr,true,false);
wrd=CTranslit::tr(wrd,CTranslit::CopticTrToCopticN,false,false);
}
else if(CTranslit::isHebrew(wrd))
{
wrd=CTranslit::tr(wrd,CTranslit::HebrewNToHebrewTr,true,false);
wrd=CTranslit::tr(wrd,CTranslit::HebrewTrToHebrewN,false,false);
}
else
{
wrd=CTranslit::tr(wrd,CTranslit::LatinNToLatinTr,true,false);
wrd=CTranslit::tr(wrd,CTranslit::LatinTrToLatinN,false,false);
}
tc.removeSelectedText();
tc.insertText(wrd);
}while(tc.movePosition(QTextCursor::NextWord));
}
if(rmSpaces()&&!is_finalized)
{
PRGD_RESTART("removing spaces ...")
tc.movePosition(QTextCursor::Start);
while(!(tc=newtd->find(" ",tc,0)).isNull())
{
PRGD("removing spaces ...")
tc.removeSelectedText();
}
}
if(isHighlightChecked())
{
QString t(txtFind->text_utf8());
if(!t.count()>0)
btHLText->setChecked(false);
else
{
QTextCharFormat cf;
cf.setForeground(messages->settings().HTfgC());
cf.setBackground(messages->settings().HTbgC());
QRegExp rt(t,Qt::CaseInsensitive);
rt.setMinimal(true);
bool reg(cmbType->currentIndex()==1),wrds(cbWordsOnly->isChecked());
PRGD_RESTART("highlighting text ...")
tc.movePosition(QTextCursor::Start);
if(wrds)
{
do
{
PRGD("highlighting text ...")
QTextCursor ntc(tc);
ntc.select(QTextCursor::WordUnderCursor);
QString st(ntc.selectedText());
if(reg)
{
if(rt.indexIn(st)!=-1)
ntc.mergeCharFormat(cf);
}
else
{
if(st.contains(t,Qt::CaseInsensitive))
ntc.mergeCharFormat(cf);
}
}while(tc.movePosition(QTextCursor::NextWord,QTextCursor::MoveAnchor,1));
}
else
{
if(reg)
while(!(tc=newtd->find(rt,tc)).isNull())
{
PRGD("highlighting text ...")
tc.mergeCharFormat(cf);
}
else
while(!(tc=newtd->find(t,tc)).isNull())
{
PRGD("highlighting text ...")
tc.mergeCharFormat(cf);
}
}
}
}
br->setDocument(newtd);
}
return true;
}
void CBookTextBrowser::finalizeContent()
{
btHLText->setChecked(false);
deleteOrigText();
setOrigText();
is_finalized=true;
}
void CBookTextBrowser::setOrigText()
{
if(!orig_text)
orig_text=br->document()->clone();
}
void CBookTextBrowser::restoreOrigText()
{
if(orig_text)
br->setDocument(orig_text);
}
void CBookTextBrowser::deleteOrigText()
{
if(orig_text)
{
delete orig_text;
orig_text=0;
}
}
/*QString CBookTextBrowser::origText() const
{
return orig_text;
}*/
void CBookTextBrowser::setPanelVisibility(bool visible)
{
widget->setVisible(visible);
}
void CBookTextBrowser::setInfoPanelVisibility(bool visible)
{
wdgInfo->setVisible(visible);
show_inf->setChecked(visible);
}
/*void CBookTextBrowser::setPanelText(QString const & text)
{
txtFind->setText(text);
}*/
/*QString CBookTextBrowser::highlightText(QString const & oldtext) const
{
QString text(oldtext);
if(cmbType->currentIndex()==1)
{
QRegExp r(inputBox().text_utf8());
r.setMinimal(true);
if(cbWordsOnly->isChecked())
{
QStringList splitted(text.split(" ",QString::KeepEmptyParts));
text.clear();
for(int x=0;x<splitted.count();x++)
{
QString bkps(splitted[x]);
QString htxt;
int p=-1;
while((p=r.indexIn(bkps))!=-1)
{
bool is_tag(CTranslit::isTag(bkps,p));
QString ms(r.cap(0));
QString pss(bkps.left(p+r.matchedLength()));
bkps.remove(0,p+r.matchedLength());
if(!is_tag)
pss.replace(ms,QString("<span style=\"color: "+messages->settings().HTfgColor()+"; background-color: "+messages->settings().HTbgColor()+"\">"+ms+"</span>"));
htxt.append(pss);
}
htxt.append(bkps);
text.append(htxt+" ");
}
return text.trimmed();
}
else
{
QString htxt;
int p=-1;
while((p=r.indexIn(text))!=-1)
{
bool is_tag(CTranslit::isTag(text,p));
QString ms(r.cap(0));
QString pss(text.left(p+r.matchedLength()));
text.remove(0,p+r.matchedLength());
if(!is_tag)
pss.replace(ms,QString("<span style=\"color: "+messages->settings().HTfgColor()+"; background-color: "+messages->settings().HTbgColor()+"\">"+ms+"</span>"));
htxt.append(pss);
}
htxt.append(text);
return htxt;
}
return text;
}
else
return text.replace(inputBox().text_utf8(),QString("<span style=\"color: "+messages->settings().HTfgColor()+"; background-color: "+messages->settings().HTbgColor()+"\">"+inputBox().text_utf8()+"</span>"));
}*/
void CBookTextBrowser::setWordsChecked(bool checked)
{
cbWordsOnly->setChecked(checked);
}
bool CBookTextBrowser::isWordsChecked() const
{
return cbWordsOnly->isChecked();
}
void CBookTextBrowser::on_cmbType_currentIndexChanged(int )
{
highlight();
slot_input_textChanged(QString());
}
void CBookTextBrowser::on_cbWordsOnly_toggled(bool )
{
highlight();
slot_input_textChanged(QString());
}
void CBookTextBrowser::keyPressEvent(QKeyEvent * event)
{
if(event->modifiers()==Qt::ControlModifier)
switch(event->key())
{
case Qt::Key_P :
widget->setVisible(!widget->isVisible());
event->accept();
break;
case Qt::Key_O :
spnFSize->setValue(spnFSize->value()+1);
event->accept();
break;
case Qt::Key_L :
spnFSize->setValue(spnFSize->value()-1);
event->accept();
break;
default:
event->ignore();
break;
}
else
event->ignore();
}
void CBookTextBrowser::setExact()
{
cmbType->setCurrentIndex(0);
}
void CBookTextBrowser::setRegExp()
{
cmbType->setCurrentIndex(1);
}
bool CBookTextBrowser::isRegExp() const
{
return cmbType->currentIndex()==1;
}
void CBookTextBrowser::on_btBottom_clicked()
{
br->moveCursor(QTextCursor::End);
}
void CBookTextBrowser::on_btFindUp_clicked()
{
QString ft(txtFind->text_utf8());
if(ft.isEmpty())
return;
//USE_CLEAN_WAIT
QRegExp rft(ft,Qt::CaseInsensitive);
rft.setMinimal(true);
bool reg(cmbType->currentIndex()==1),wrds(cbWordsOnly->isChecked());
if(wrds)
{
USE_CLEAN_WAIT
CProgressDialog pd;
QTime time;
time.start();
bool prg(false);
QTextCursor tc(br->textCursor());
QTextDocument * newtd(br->document());
bool catched(false);
if(tc.hasSelection())
{
tc.setPosition(tc.selectionStart());
tc.movePosition(QTextCursor::StartOfWord);
tc.movePosition(QTextCursor::PreviousWord,QTextCursor::MoveAnchor,1);
}
do
{
PRGD("detecting occurrence ...")
QTextCursor snc(tc);
snc.select(QTextCursor::WordUnderCursor);
QString st(snc.selectedText());
if(reg)
{
if(rft.indexIn(st)!=-1)
{
//fnc=fnc.document()->find(rft,nc);
catched=true;
break;
}
}
else
{
if(st.contains(ft,Qt::CaseInsensitive))
{
//fnc=fnc.document()->find(ft,nc);
catched=true;
break;
}
}
}while(tc.movePosition(QTextCursor::PreviousWord,QTextCursor::MoveAnchor,1));
if(!catched)
br->moveCursor(QTextCursor::Start);
else
{
if(tc.isNull())
br->moveCursor(QTextCursor::Start);
else
{
tc.select(QTextCursor::WordUnderCursor);
br->setTextCursor(tc);
}
}
/*QTextCursor nc;
if(reg)
nc=br->document()->find(rft,br->textCursor(),QTextDocument::FindBackward|QTextDocument::FindWholeWords);
else
nc=br->document()->find(ft,br->textCursor(),QTextDocument::FindBackward|QTextDocument::FindWholeWords);
if(nc.isNull())
br->moveCursor(QTextCursor::Start);
else
br->setTextCursor(nc);*/
}
else
{
QTextCursor nc;
if(reg)
nc=br->document()->find(rft,br->textCursor(),QTextDocument::FindBackward);
else
nc=br->document()->find(ft,br->textCursor(),QTextDocument::FindBackward);
if(nc.isNull())
br->moveCursor(QTextCursor::Start);
else
br->setTextCursor(nc);
}
}
void CBookTextBrowser::allowChangeScript()
{
txtFind->allowChangeScript();
}
void CBookTextBrowser::on_btAction_clicked()
{
bt_action=true;
on_br_customContextMenuRequested(btAction->mapToGlobal(QPoint(0,0)));
}
void CBookTextBrowser::on_br_textChanged()
{
lblInf->setText(QString::number(br->document()->lineCount()));
lblChar->setText(QString::number(br->document()->characterCount()));
}
void CBookTextBrowser::on_btSaveAs_clicked()
{
QFileDialog fd(this,"save document",QString(),"html files (*.html *.htm);;text files (*.txt);;all files (*)");
fd.setFileMode(QFileDialog::AnyFile);
fd.setAcceptMode(QFileDialog::AcceptSave);
if(fd.exec()==QDialog::Accepted)
{
if(fd.selectedFiles().count()>0)
{
QString fn(fd.selectedFiles().first());
QFile f(fn);
if(f.open(QIODevice::WriteOnly))
{
int e;
bool ishtml;
if((ishtml=(fd.selectedFilter().startsWith("html files"))))
e=f.write(br->document()->toHtml().toUtf8());
else
e=f.write(br->document()->toPlainText().toUtf8());
if(e==-1)
messages->MsgErr("cannot write into file '"+f.fileName()+"'");
else
{
messages->MsgInf(QString(ishtml?"html":"txt")+" file '"+f.fileName()+"' saved");
messages->MsgOk();
}
f.close();
}
else
messages->MsgErr("cannot open file '"+f.fileName()+"' for writing");
}
}
}
void CBookTextBrowser::on_cbWrap_clicked(bool checked)
{
if(checked)
br->setWordWrapMode(QTextOption::WordWrap);
else
br->setWordWrapMode(QTextOption::NoWrap);
}
void CBookTextBrowser::on_br_sourceChanged(QUrl url)
{
url.setFragment(QString::null);
if(url!=lasturl)
{
cbRmAccents->setChecked(false);
cbRmSpaces->setChecked(false);
btHLText->setChecked(false);
deleteOrigText();
//setOrigText();
//messages->MsgMsg("source changed from "+lasturl.toString()+" to "+url.toString());
lasturl=url;
//prg=false;
messages->MsgMsg(tr("page loaded: ")+lasturl.toString());
}
//messages->MsgMsg("reloaded");
}
void CBookTextBrowser::beforeReload()
{
lasturl.clear();
}
void CBookTextBrowser::on_cbAllowFont_clicked(bool checked)
{
if(checked)
on_spnFSize_valueChanged(spnFSize->value());
else
br->setFont(QFont());
}
void CBookTextBrowser::on_br_backwardAvailable(bool available)
{
emit historyFBChanged(Backward,available);
}
void CBookTextBrowser::on_br_forwardAvailable(bool available)
{
emit historyFBChanged(Forward,available);
}
void CBookTextBrowser::setFont(QFont const & f)
{
cmbF->setCurrentFont(f);
spnFSize->setValue(f.pointSize());
}