Split the preview code for clarity

This commit is contained in:
Jean-Francois Dockes 2015-11-09 15:40:11 +01:00
parent e33904d65c
commit 759c41c936
7 changed files with 450 additions and 255 deletions

View file

@ -0,0 +1,75 @@
/* Copyright (C) 2014 J.F.Dockes
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string>
#include "debuglog.h"
#include "preview_load.h"
#include "internfile.h"
#include "rcldoc.h"
#include "pathut.h"
#include "cancelcheck.h"
#include "rclconfig.h"
LoadThread::LoadThread(RclConfig *config, const Rcl::Doc& idc,
bool pvhtm, QObject *parent)
: QThread(parent), status(1), m_idoc(idc), m_previewHtml(pvhtm),
m_config(*config)
{
// Save log level while we're running in the calling thread.
m_loglevel = DebugLog::getdbl()->getlevel();
}
void LoadThread::run()
{
DebugLog::getdbl()->setloglevel(m_loglevel);
FileInterner interner(m_idoc, &m_config, FileInterner::FIF_forPreview);
FIMissingStore mst;
interner.setMissingStore(&mst);
// Even when previewHtml is set, we don't set the interner's
// target mtype to html because we do want the html filter to
// do its work: we won't use the text/plain, but we want the
// text/html to be converted to utf-8 (for highlight processing)
try {
string ipath = m_idoc.ipath;
FileInterner::Status ret = interner.internfile(fdoc, ipath);
if (ret == FileInterner::FIDone || ret == FileInterner::FIAgain) {
// FIAgain is actually not nice here. It means that the record
// for the *file* of a multidoc was selected. Actually this
// shouldn't have had a preview link at all, but we don't know
// how to handle it now. Better to show the first doc than
// a mysterious error. Happens when the file name matches a
// a search term.
status = 0;
// If we prefer HTML and it is available, replace the
// text/plain document text
if (m_previewHtml && !interner.get_html().empty()) {
fdoc.text = interner.get_html();
fdoc.mimetype = "text/html";
}
tmpimg = interner.get_imgtmp();
} else {
fdoc.mimetype = interner.getMimetype();
mst.getMissingExternal(missing);
status = -1;
}
} catch (CancelExcept) {
LOGDEB(("LoadThread: cancelled\n"));
status = -1;
}
}

59
src/qtgui/preview_load.h Normal file
View file

@ -0,0 +1,59 @@
/* Copyright (C) 2015 J.F.Dockes
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _PVW_LOAD_H_INCLUDED_
#define _PVW_LOAD_H_INCLUDED_
#include <string>
#include <QThread>
#include "rcldoc.h"
#include "pathut.h"
#include "rclconfig.h"
/*
* A thread to perform the file reading / format conversion work for preview
*/
class LoadThread : public QThread {
Q_OBJECT;
public:
LoadThread(RclConfig *conf,
const Rcl::Doc& idoc, bool pvhtml, QObject *parent = 0);
virtual ~LoadThread() {
}
virtual void run();
public:
// The results are returned through public members.
int status;
Rcl::Doc fdoc;
TempFile tmpimg;
std::string missing;
private:
Rcl::Doc m_idoc;
int m_loglevel;
bool m_previewHtml;
RclConfig m_config;
};
#endif /* _PVW_LOAD_H_INCLUDED_ */

View file

@ -0,0 +1,187 @@
/* Copyright (C) 2014 J.F.Dockes
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "autoconfig.h"
#include <stdio.h>
#include <string>
#include <QString>
#include <QStringList>
#include "preview_plaintorich.h"
#include "plaintorich.h"
#include "debuglog.h"
#include "guiutils.h"
#include "cancelcheck.h"
using namespace std;
PlainToRichQtPreview::PlainToRichQtPreview()
{
clear();
}
void PlainToRichQtPreview::clear()
{
m_curanchor = 1;
m_lastanchor = 0;
m_groupanchors.clear();
m_groupcuranchors.clear();
}
bool PlainToRichQtPreview::haveAnchors()
{
return m_lastanchor != 0;
}
string PlainToRichQtPreview::PlainToRichQtPreview::header()
{
if (!m_inputhtml) {
switch (prefs.previewPlainPre) {
case PrefsPack::PP_BR:
m_eolbr = true;
return "<qt><head><title></title></head><body>";
case PrefsPack::PP_PRE:
m_eolbr = false;
return "<qt><head><title></title></head><body><pre>";
case PrefsPack::PP_PREWRAP:
m_eolbr = false;
return "<qt><head><title></title></head><body>"
"<pre style=\"white-space: pre-wrap\">";
}
}
return cstr_null;
}
string PlainToRichQtPreview::startMatch(unsigned int grpidx)
{
LOGDEB2(("startMatch, grpidx %u\n", grpidx));
grpidx = m_hdata->grpsugidx[grpidx];
LOGDEB2(("startMatch, ugrpidx %u\n", grpidx));
m_groupanchors[grpidx].push_back(++m_lastanchor);
m_groupcuranchors[grpidx] = 0;
return string("<span style='color: ").
append((const char *)(prefs.qtermcolor.toUtf8())).
append(";font-weight: bold;").
append("'>").
append("<a name=\"").
append(termAnchorName(m_lastanchor)).
append("\">");
}
string PlainToRichQtPreview::endMatch()
{
return string("</a></span>");
}
string PlainToRichQtPreview::termAnchorName(int i) const
{
static const char *termAnchorNameBase = "TRM";
char acname[sizeof(termAnchorNameBase) + 20];
sprintf(acname, "%s%d", termAnchorNameBase, i);
return string(acname);
}
string PlainToRichQtPreview::startChunk()
{
return "<pre>";
}
int PlainToRichQtPreview::nextAnchorNum(int grpidx)
{
LOGDEB2(("nextAnchorNum: group %d\n", grpidx));
map<unsigned int, unsigned int>::iterator curit =
m_groupcuranchors.find(grpidx);
map<unsigned int, vector<int> >::iterator vecit =
m_groupanchors.find(grpidx);
if (grpidx == -1 || curit == m_groupcuranchors.end() ||
vecit == m_groupanchors.end()) {
if (m_curanchor >= m_lastanchor)
m_curanchor = 1;
else
m_curanchor++;
} else {
if (curit->second >= vecit->second.size() -1)
m_groupcuranchors[grpidx] = 0;
else
m_groupcuranchors[grpidx]++;
m_curanchor = vecit->second[m_groupcuranchors[grpidx]];
LOGDEB2(("nextAnchorNum: curanchor now %d\n", m_curanchor));
}
return m_curanchor;
}
int PlainToRichQtPreview::prevAnchorNum(int grpidx)
{
map<unsigned int, unsigned int>::iterator curit =
m_groupcuranchors.find(grpidx);
map<unsigned int, vector<int> >::iterator vecit =
m_groupanchors.find(grpidx);
if (grpidx == -1 || curit == m_groupcuranchors.end() ||
vecit == m_groupanchors.end()) {
if (m_curanchor <= 1)
m_curanchor = m_lastanchor;
else
m_curanchor--;
} else {
if (curit->second <= 0)
m_groupcuranchors[grpidx] = vecit->second.size() -1;
else
m_groupcuranchors[grpidx]--;
m_curanchor = vecit->second[m_groupcuranchors[grpidx]];
}
return m_curanchor;
}
QString PlainToRichQtPreview::curAnchorName() const
{
return QString::fromUtf8(termAnchorName(m_curanchor).c_str());
}
ToRichThread::ToRichThread(const string &i, const HighlightData& hd,
STD_SHARED_PTR<PlainToRichQtPreview> ptr,
QStringList& qrichlist,
QObject *parent)
: QThread(parent), m_input(i), m_hdata(hd), m_ptr(ptr), m_output(qrichlist)
{
m_loglevel = DebugLog::getdbl()->getlevel();
}
// Insert into editor by chunks so that the top becomes visible
// earlier for big texts. This provokes some artifacts (adds empty line),
// so we can't set it too low.
#define CHUNKL 500*1000
void ToRichThread::run()
{
DebugLog::getdbl()->setloglevel(m_loglevel);
list<string> out;
try {
m_ptr->plaintorich(m_input, out, m_hdata, CHUNKL);
} catch (CancelExcept) {
return;
}
// Convert C++ string list to QString list
for (list<string>::iterator it = out.begin();
it != out.end(); it++) {
m_output.push_back(QString::fromUtf8(it->c_str(), it->length()));
}
}

View file

@ -0,0 +1,74 @@
/* Copyright (C) 2015 J.F.Dockes
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _PREVIEW_PLAINTORICH_H_INCLUDED_
#define _PREVIEW_PLAINTORICH_H_INCLUDED_
#include "autoconfig.h"
#include <map>
#include <string>
#include <vector>
#include MEMORY_INCLUDE
#include <QThread>
#include <QStringList>
#include "plaintorich.h"
/** Preview text highlighter */
class PlainToRichQtPreview : public PlainToRich {
public:
PlainToRichQtPreview();
void clear();
bool haveAnchors();
virtual string header();
virtual string startMatch(unsigned int grpidx);
virtual string endMatch();
virtual string termAnchorName(int i) const;
virtual string startChunk();
int nextAnchorNum(int grpidx);
int prevAnchorNum(int grpidx);
QString curAnchorName() const;
private:
int m_curanchor;
int m_lastanchor;
// Lists of anchor numbers (match locations) for the term (groups)
// in the query (the map key is and index into HighlightData.groups).
std::map<unsigned int, std::vector<int> > m_groupanchors;
std::map<unsigned int, unsigned int> m_groupcuranchors;
};
/* A thread to convert to rich text (mark search terms) */
class ToRichThread : public QThread {
Q_OBJECT;
public:
ToRichThread(const string &i, const HighlightData& hd,
STD_SHARED_PTR<PlainToRichQtPreview> ptr,
QStringList& qrichlst, // Output
QObject *parent = 0);
virtual void run();
private:
int m_loglevel;
const string &m_input;
const HighlightData &m_hdata;
STD_SHARED_PTR<PlainToRichQtPreview> m_ptr;
QStringList &m_output;
};
#endif /* _PREVIEW_PLAINTORICH_H_INCLUDED_ */

View file

@ -49,7 +49,6 @@
#include "pathut.h" #include "pathut.h"
#include "internfile.h" #include "internfile.h"
#include "recoll.h" #include "recoll.h"
#include "plaintorich.h"
#include "smallut.h" #include "smallut.h"
#include "chrono.h" #include "chrono.h"
#include "wipedir.h" #include "wipedir.h"
@ -58,6 +57,8 @@
#include "guiutils.h" #include "guiutils.h"
#include "docseqhist.h" #include "docseqhist.h"
#include "rclhelp.h" #include "rclhelp.h"
#include "preview_load.h"
#include "preview_plaintorich.h"
static const QKeySequence closeKS(Qt::Key_Escape); static const QKeySequence closeKS(Qt::Key_Escape);
static const QKeySequence nextDocInTabKS(Qt::ShiftModifier+Qt::Key_Down); static const QKeySequence nextDocInTabKS(Qt::ShiftModifier+Qt::Key_Down);
@ -65,129 +66,6 @@ static const QKeySequence prevDocInTabKS(Qt::ShiftModifier+Qt::Key_Up);
static const QKeySequence closeTabKS(Qt::ControlModifier+Qt::Key_W); static const QKeySequence closeTabKS(Qt::ControlModifier+Qt::Key_W);
static const QKeySequence printTabKS(Qt::ControlModifier+Qt::Key_P); static const QKeySequence printTabKS(Qt::ControlModifier+Qt::Key_P);
// Subclass plainToRich to add <termtag>s and anchors to the preview text
class PlainToRichQtPreview : public PlainToRich {
public:
PlainToRichQtPreview()
: m_curanchor(1), m_lastanchor(0) {
}
void clear() {
m_curanchor = 1;
m_lastanchor = 0;
m_groupanchors.clear();
m_groupcuranchors.clear();
}
bool haveAnchors() {
return m_lastanchor != 0;
}
virtual string header() {
if (!m_inputhtml) {
switch (prefs.previewPlainPre) {
case PrefsPack::PP_BR:
m_eolbr = true;
return "<qt><head><title></title></head><body>";
case PrefsPack::PP_PRE:
m_eolbr = false;
return "<qt><head><title></title></head><body><pre>";
case PrefsPack::PP_PREWRAP:
m_eolbr = false;
return "<qt><head><title></title></head><body>"
"<pre style=\"white-space: pre-wrap\">";
}
}
return cstr_null;
}
virtual string startMatch(unsigned int grpidx) {
LOGDEB2(("startMatch, grpidx %u\n", grpidx));
grpidx = m_hdata->grpsugidx[grpidx];
LOGDEB2(("startMatch, ugrpidx %u\n", grpidx));
m_groupanchors[grpidx].push_back(++m_lastanchor);
m_groupcuranchors[grpidx] = 0;
return string("<span style='color: ").
append((const char *)(prefs.qtermcolor.toUtf8())).
append(";font-weight: bold;").
append("'>").
append("<a name=\"").
append(termAnchorName(m_lastanchor)).
append("\">");
}
virtual string endMatch() {
return string("</a></span>");
}
virtual string termAnchorName(int i) const {
static const char *termAnchorNameBase = "TRM";
char acname[sizeof(termAnchorNameBase) + 20];
sprintf(acname, "%s%d", termAnchorNameBase, i);
return string(acname);
}
virtual string startChunk() {
return "<pre>";
}
int nextAnchorNum(int grpidx) {
LOGDEB2(("nextAnchorNum: group %d\n", grpidx));
map<unsigned int, unsigned int>::iterator curit =
m_groupcuranchors.find(grpidx);
map<unsigned int, vector<int> >::iterator vecit =
m_groupanchors.find(grpidx);
if (grpidx == -1 || curit == m_groupcuranchors.end() ||
vecit == m_groupanchors.end()) {
if (m_curanchor >= m_lastanchor)
m_curanchor = 1;
else
m_curanchor++;
} else {
if (curit->second >= vecit->second.size() -1)
m_groupcuranchors[grpidx] = 0;
else
m_groupcuranchors[grpidx]++;
m_curanchor = vecit->second[m_groupcuranchors[grpidx]];
LOGDEB2(("nextAnchorNum: curanchor now %d\n", m_curanchor));
}
return m_curanchor;
}
int prevAnchorNum(int grpidx) {
map<unsigned int, unsigned int>::iterator curit =
m_groupcuranchors.find(grpidx);
map<unsigned int, vector<int> >::iterator vecit =
m_groupanchors.find(grpidx);
if (grpidx == -1 || curit == m_groupcuranchors.end() ||
vecit == m_groupanchors.end()) {
if (m_curanchor <= 1)
m_curanchor = m_lastanchor;
else
m_curanchor--;
} else {
if (curit->second <= 0)
m_groupcuranchors[grpidx] = vecit->second.size() -1;
else
m_groupcuranchors[grpidx]--;
m_curanchor = vecit->second[m_groupcuranchors[grpidx]];
}
return m_curanchor;
}
QString curAnchorName() const {
return QString::fromUtf8(termAnchorName(m_curanchor).c_str());
}
private:
int m_curanchor;
int m_lastanchor;
// Lists of anchor numbers (match locations) for the term (groups)
// in the query (the map key is and index into HighlightData.groups).
map<unsigned int, vector<int> > m_groupanchors;
map<unsigned int, unsigned int> m_groupcuranchors;
};
void Preview::init() void Preview::init()
{ {
setObjectName("Preview"); setObjectName("Preview");
@ -713,91 +591,15 @@ void Preview::emitWordSelect(QString word)
beginning of the text displayed faster beginning of the text displayed faster
*/ */
/* A thread to to the file reading / format conversion */
class LoadThread : public QThread {
int *statusp;
Rcl::Doc& out;
const Rcl::Doc& idoc;
int loglevel;
public:
string missing;
TempFile imgtmp;
LoadThread(int *stp, Rcl::Doc& odoc, const Rcl::Doc& idc)
: statusp(stp), out(odoc), idoc(idc)
{
loglevel = DebugLog::getdbl()->getlevel();
}
~LoadThread() {
}
virtual void run() {
DebugLog::getdbl()->setloglevel(loglevel);
FileInterner interner(idoc, theconfig, FileInterner::FIF_forPreview);
FIMissingStore mst;
interner.setMissingStore(&mst);
// Even when previewHtml is set, we don't set the interner's
// target mtype to html because we do want the html filter to
// do its work: we won't use the text/plain, but we want the
// text/html to be converted to utf-8 (for highlight processing)
try {
string ipath = idoc.ipath;
FileInterner::Status ret = interner.internfile(out, ipath);
if (ret == FileInterner::FIDone || ret == FileInterner::FIAgain) {
// FIAgain is actually not nice here. It means that the record
// for the *file* of a multidoc was selected. Actually this
// shouldn't have had a preview link at all, but we don't know
// how to handle it now. Better to show the first doc than
// a mysterious error. Happens when the file name matches a
// a search term.
*statusp = 0;
// If we prefer html and it is available, replace the
// text/plain document text
if (prefs.previewHtml && !interner.get_html().empty()) {
out.text = interner.get_html();
out.mimetype = "text/html";
}
imgtmp = interner.get_imgtmp();
} else {
out.mimetype = interner.getMimetype();
mst.getMissingExternal(missing);
*statusp = -1;
}
} catch (CancelExcept) {
*statusp = -1;
}
}
};
// Insert into editor by chunks so that the top becomes visible // Insert into editor by chunks so that the top becomes visible
// earlier for big texts. This provokes some artifacts (adds empty line), // earlier for big texts. This provokes some artifacts (adds empty line),
// so we can't set it too low. // so we can't set it too low.
#define CHUNKL 500*1000 #define CHUNKL 500*1000
/* A thread to convert to rich text (mark search terms) */ // Make sure we don't ever reenter loadDocInCurrentTab: note that I
class ToRichThread : public QThread { // don't think it's actually possible, this must be the result of a
string &in; // misguided debug session.
const HighlightData &hdata;
list<string> &out;
int loglevel;
PlainToRichQtPreview *ptr;
public:
ToRichThread(string &i, const HighlightData& hd, list<string> &o,
PlainToRichQtPreview *_ptr)
: in(i), hdata(hd), out(o), ptr(_ptr)
{
loglevel = DebugLog::getdbl()->getlevel();
}
virtual void run()
{
DebugLog::getdbl()->setloglevel(loglevel);
try {
ptr->plaintorich(in, out, hdata, CHUNKL);
} catch (CancelExcept) {
}
}
};
class LoadGuard { class LoadGuard {
bool *m_bp; bool *m_bp;
public: public:
@ -829,9 +631,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// Load and convert document // Load and convert document
// idoc came out of the index data (main text and some fields missing). // idoc came out of the index data (main text and some fields missing).
// fdoc is the complete one what we are going to extract from storage. // fdoc is the complete one what we are going to extract from storage.
Rcl::Doc fdoc; LoadThread lthr(theconfig, idoc, prefs.previewHtml, this);
int status = 1;
LoadThread lthr(&status, fdoc, idoc);
connect(&lthr, SIGNAL(finished()), &loop, SLOT(quit())); connect(&lthr, SIGNAL(finished()), &loop, SLOT(quit()));
lthr.start(); lthr.start();
@ -843,17 +643,18 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
if (progress.wasCanceled()) { if (progress.wasCanceled()) {
CancelCheck::instance().setCancel(); CancelCheck::instance().setCancel();
} }
if (i == 2) if (i == 1)
progress.show(); progress.show();
} }
LOGDEB(("loadDocInCurrentTab: after file load: cancel %d status %d" LOGDEB(("loadDocInCurrentTab: after file load: cancel %d status %d"
" text length %d\n", " text length %d\n",
CancelCheck::instance().cancelState(), status, fdoc.text.length())); CancelCheck::instance().cancelState(), lthr.status,
lthr.fdoc.text.length()));
if (CancelCheck::instance().cancelState()) if (CancelCheck::instance().cancelState())
return false; return false;
if (status != 0) { if (lthr.status != 0) {
progress.close(); progress.close();
QString explain; QString explain;
if (!lthr.missing.empty()) { if (!lthr.missing.empty()) {
@ -863,10 +664,14 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
QMessageBox::warning(0, "Recoll", QMessageBox::warning(0, "Recoll",
tr("Can't turn doc into internal " tr("Can't turn doc into internal "
"representation for ") + "representation for ") +
fdoc.mimetype.c_str() + explain); lthr.fdoc.mimetype.c_str() + explain);
} else { } else {
QMessageBox::warning(0, "Recoll", if (progress.wasCanceled()) {
tr("Error while loading file")); //QMessageBox::warning(0, "Recoll", tr("Canceled"));
} else {
QMessageBox::warning(0, "Recoll",
tr("Error while loading file"));
}
} }
return false; return false;
@ -879,12 +684,11 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// We don't do the highlighting for very big texts: too long. We // We don't do the highlighting for very big texts: too long. We
// should at least do special char escaping, in case a '&' or '<' // should at least do special char escaping, in case a '&' or '<'
// somehow slipped through previous processing. // somehow slipped through previous processing.
bool highlightTerms = fdoc.text.length() < bool highlightTerms = lthr.fdoc.text.length() <
(unsigned long)prefs.maxhltextmbs * 1024 * 1024; (unsigned long)prefs.maxhltextmbs * 1024 * 1024;
// Final text is produced in chunks so that we can display the top // Final text is produced in chunks so that we can display the top
// while still inserting at bottom // while still inserting at bottom
list<QString> qrichlst;
PreviewTextEdit *editor = currentEditor(); PreviewTextEdit *editor = currentEditor();
editor->m_plaintorich->clear(); editor->m_plaintorich->clear();
@ -906,33 +710,24 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
editor->setHtml(""); editor->setHtml("");
editor->m_format = Qt::RichText; editor->m_format = Qt::RichText;
bool inputishtml = !fdoc.mimetype.compare("text/html"); bool inputishtml = !lthr.fdoc.mimetype.compare("text/html");
QStringList qrichlst;
#if 0
// For testing qtextedit bugs... #if 1
highlightTerms = true;
const char *textlist[] =
{
"Du plain text avec un\n <termtag>termtag</termtag> fin de ligne:",
"texte apres le tag\n",
};
const int listl = sizeof(textlist) / sizeof(char*);
for (int i = 0 ; i < listl ; i++)
qrichlst.push_back(QString::fromUtf8(textlist[i]));
#else
if (highlightTerms) { if (highlightTerms) {
progress.setLabelText(tr("Creating preview text")); progress.setLabelText(tr("Creating preview text"));
qApp->processEvents(); qApp->processEvents();
if (inputishtml) { if (inputishtml) {
LOGDEB1(("Preview: got html %s\n", fdoc.text.c_str())); LOGDEB1(("Preview: got html %s\n", lthr.fdoc.text.c_str()));
editor->m_plaintorich->set_inputhtml(true); editor->m_plaintorich->set_inputhtml(true);
} else { } else {
LOGDEB1(("Preview: got plain %s\n", fdoc.text.c_str())); LOGDEB1(("Preview: got plain %s\n", lthr.fdoc.text.c_str()));
editor->m_plaintorich->set_inputhtml(false); editor->m_plaintorich->set_inputhtml(false);
} }
list<string> richlst;
ToRichThread rthr(fdoc.text, m_hData, richlst, editor->m_plaintorich); ToRichThread rthr(lthr.fdoc.text, m_hData, editor->m_plaintorich,
qrichlst, this);
connect(&rthr, SIGNAL(finished()), &loop, SLOT(quit())); connect(&rthr, SIGNAL(finished()), &loop, SLOT(quit()));
rthr.start(); rthr.start();
@ -948,22 +743,18 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// Conversion to rich text done // Conversion to rich text done
if (CancelCheck::instance().cancelState()) { if (CancelCheck::instance().cancelState()) {
if (richlst.size() == 0 || richlst.front().length() == 0) { if (qrichlst.size() == 0 || qrichlst.front().size() == 0) {
// We can't call closeCurrentTab here as it might delete // We can't call closeCurrentTab here as it might delete
// the object which would be a nasty surprise to our // the object which would be a nasty surprise to our
// caller. // caller.
return false; return false;
} else { } else {
richlst.back() += "<b>Cancelled !</b>"; qrichlst.back() += "<b>Cancelled !</b>";
} }
} }
// Convert C++ string list to QString list
for (list<string>::iterator it = richlst.begin();
it != richlst.end(); it++) {
qrichlst.push_back(QString::fromUtf8(it->c_str(), it->length()));
}
} else { } else {
LOGDEB(("Preview: no hilighting\n")); LOGDEB(("Preview: no hilighting, loading %d bytes\n",
int(lthr.fdoc.text.size())));
// No plaintorich() call. In this case, either the text is // No plaintorich() call. In this case, either the text is
// html and the html quoting is hopefully correct, or it's // html and the html quoting is hopefully correct, or it's
// plain-text and there is no need to escape special // plain-text and there is no need to escape special
@ -971,7 +762,8 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// top is displayed faster), but we must not cut tags, and // top is displayed faster), but we must not cut tags, and
// it's too difficult on html. For text we do the splitting on // it's too difficult on html. For text we do the splitting on
// a QString to avoid utf8 issues. // a QString to avoid utf8 issues.
QString qr = QString::fromUtf8(fdoc.text.c_str(), fdoc.text.length()); QString qr = QString::fromUtf8(lthr.fdoc.text.c_str(),
lthr.fdoc.text.length());
int l = 0; int l = 0;
if (inputishtml) { if (inputishtml) {
qrichlst.push_back(qr); qrichlst.push_back(qr);
@ -984,6 +776,16 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
} }
} }
} }
#else // For testing qtextedit bugs...
highlightTerms = true;
const char *textlist[] =
{
"Du plain text avec un\n <termtag>termtag</termtag> fin de ligne:",
"texte apres le tag\n",
};
const int listl = sizeof(textlist) / sizeof(char*);
for (int i = 0 ; i < listl ; i++)
qrichlst.push_back(QString::fromUtf8(textlist[i]));
#endif #endif
@ -991,7 +793,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// Load text into editor window. // Load text into editor window.
progress.setLabelText(tr("Loading preview text into editor")); progress.setLabelText(tr("Loading preview text into editor"));
qApp->processEvents(); qApp->processEvents();
for (list<QString>::iterator it = qrichlst.begin(); for (QStringList::iterator it = qrichlst.begin();
it != qrichlst.end(); it++) { it != qrichlst.end(); it++) {
qApp->processEvents(); qApp->processEvents();
@ -1016,10 +818,10 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// Maybe the text was actually empty ? Switch to fields then. Else free-up // Maybe the text was actually empty ? Switch to fields then. Else free-up
// the text memory in the loaded document. We still have a copy of the text // the text memory in the loaded document. We still have a copy of the text
// in editor->m_richtxt // in editor->m_richtxt
bool textempty = fdoc.text.empty(); bool textempty = lthr.fdoc.text.empty();
if (!textempty) if (!textempty)
fdoc.text.clear(); lthr.fdoc.text.clear();
editor->m_fdoc = fdoc; editor->m_fdoc = lthr.fdoc;
editor->m_dbdoc = idoc; editor->m_dbdoc = idoc;
if (textempty) if (textempty)
editor->displayFields(); editor->displayFields();
@ -1032,7 +834,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// there is an ipath that it won't understand, we need a temp file: // there is an ipath that it won't understand, we need a temp file:
theconfig->setKeyDir(path_getfather(fn)); theconfig->setKeyDir(path_getfather(fn));
if (fn.empty() || !idoc.ipath.empty()) { if (fn.empty() || !idoc.ipath.empty()) {
TempFile temp = lthr.imgtmp; TempFile temp = lthr.tmpimg;
if (temp) { if (temp) {
LOGDEB1(("Preview: load: got temp file from internfile\n")); LOGDEB1(("Preview: load: got temp file from internfile\n"));
} else if (!FileInterner::idocToFile(temp, string(), } else if (!FileInterner::idocToFile(temp, string(),
@ -1089,8 +891,8 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
} }
PreviewTextEdit::PreviewTextEdit(QWidget* parent, const char* nm, Preview *pv) PreviewTextEdit::PreviewTextEdit(QWidget* parent, const char* nm, Preview *pv)
: QTextBrowser(parent), m_preview(pv), : QTextBrowser(parent), m_preview(pv),
m_plaintorich(new PlainToRichQtPreview()), m_plaintorich(new PlainToRichQtPreview()),
m_dspflds(false), m_docnum(-1) m_dspflds(false), m_docnum(-1)
{ {
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
@ -1101,11 +903,6 @@ PreviewTextEdit::PreviewTextEdit(QWidget* parent, const char* nm, Preview *pv)
setOpenLinks(false); setOpenLinks(false);
} }
PreviewTextEdit::~PreviewTextEdit()
{
delete m_plaintorich;
}
void PreviewTextEdit::createPopupMenu(const QPoint& pos) void PreviewTextEdit::createPopupMenu(const QPoint& pos)
{ {
LOGDEB1(("PreviewTextEdit::createPopupMenu()\n")); LOGDEB1(("PreviewTextEdit::createPopupMenu()\n"));

View file

@ -56,7 +56,6 @@ class PreviewTextEdit : public PREVIEW_PARENTCLASS {
Q_OBJECT; Q_OBJECT;
public: public:
PreviewTextEdit(QWidget* parent, const char* name, Preview *pv); PreviewTextEdit(QWidget* parent, const char* name, Preview *pv);
virtual ~PreviewTextEdit();
void moveToAnchor(const QString& name); void moveToAnchor(const QString& name);
enum DspType {PTE_DSPTXT, PTE_DSPFLDS, PTE_DSPIMG}; enum DspType {PTE_DSPTXT, PTE_DSPFLDS, PTE_DSPIMG};
@ -74,7 +73,7 @@ protected:
private: private:
Preview *m_preview; Preview *m_preview;
PlainToRichQtPreview *m_plaintorich; STD_SHARED_PTR<PlainToRichQtPreview> m_plaintorich;
bool m_dspflds; bool m_dspflds;
string m_url; // filename for this tab string m_url; // filename for this tab

View file

@ -26,6 +26,8 @@ HEADERS += \
idxsched.h \ idxsched.h \
listdialog.h \ listdialog.h \
preview_w.h \ preview_w.h \
preview_load.h \
preview_plaintorich.h \
ptrans_w.h \ ptrans_w.h \
rclhelp.h \ rclhelp.h \
rclmain_w.h \ rclmain_w.h \
@ -52,6 +54,8 @@ SOURCES += \
main.cpp \ main.cpp \
multisave.cpp \ multisave.cpp \
preview_w.cpp \ preview_w.cpp \
preview_load.cpp \
preview_plaintorich.cpp \
ptrans_w.cpp \ ptrans_w.cpp \
rclhelp.cpp \ rclhelp.cpp \
rclmain_w.cpp \ rclmain_w.cpp \