diff --git a/src/VERSION b/src/VERSION index feaae22b..105be7fc 100644 --- a/src/VERSION +++ b/src/VERSION @@ -1 +1 @@ -1.13.0 +20091128 diff --git a/src/internfile/mimehandler.cpp b/src/internfile/mimehandler.cpp index 47b05ac3..557e5832 100644 --- a/src/internfile/mimehandler.cpp +++ b/src/internfile/mimehandler.cpp @@ -50,16 +50,24 @@ static Dijon::Filter *mhFactory(const string &mime) { string lmime(mime); stringtolower(lmime); - if ("text/plain" == lmime) + if ("text/plain" == lmime) { return new MimeHandlerText(lmime); - else if ("text/html" == lmime) + } else if ("text/html" == lmime) { return new MimeHandlerHtml(lmime); - else if ("text/x-mail" == lmime) + } else if ("text/x-mail" == lmime) { return new MimeHandlerMbox(lmime); - else if ("message/rfc822" == lmime) + } else if ("message/rfc822" == lmime) { return new MimeHandlerMail(lmime); - else + } else if (lmime.find("text/") == 0) { + // Try to handle unknown text/xx as text/plain. This + // only happen if the text/xx was defined as "internal" in + // mimeconf, not at random. For programs, for example this + // allows indexing and previewing as text/plain (no filter + // exec) but still opening with a specific editor. + return new MimeHandlerText(lmime); + } else { return new MimeHandlerUnknown(lmime); + } } /** diff --git a/src/kde/kioslave/recoll/htmlif.cpp b/src/kde/kioslave/recoll/htmlif.cpp index b122a614..af1e7b16 100644 --- a/src/kde/kioslave/recoll/htmlif.cpp +++ b/src/kde/kioslave/recoll/htmlif.cpp @@ -223,7 +223,7 @@ public: "
"); + string("
");
}
}
virtual string startMatch() {return string("");}
diff --git a/src/qtgui/preview_w.cpp b/src/qtgui/preview_w.cpp
index 0943d855..cf090b87 100644
--- a/src/qtgui/preview_w.cpp
+++ b/src/qtgui/preview_w.cpp
@@ -99,6 +99,10 @@ using std::pair;
#include "rclhelp.h"
+#ifndef MIN
+#define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+
// QTextEdit's scrollToAnchor() is supposed to make the anchor visible, but
// actually, it only moves to the top of the paragraph containing the anchor.
// As we only have one paragraph, this doesnt' help a lot (qt3 and qt4)
@@ -111,6 +115,7 @@ using std::pair;
// even installed under qt4. We use a local copy, which is not nice.
void PreviewTextEdit::moveToAnchor(const QString& name)
{
+ LOGDEB0(("PreviewTextEdit::moveToAnchor\n"));
if (name.isEmpty())
return;
sync();
@@ -245,10 +250,11 @@ void Preview::closeEvent(QCloseEvent *e)
bool Preview::eventFilter(QObject *target, QEvent *event)
{
+ LOGDEB2(("Preview::eventFilter()\n"));
if (event->type() != QEvent::KeyPress)
return false;
- LOGDEB1(("Preview::eventFilter: keyEvent\n"));
+ LOGDEB2(("Preview::eventFilter: keyEvent\n"));
PreviewTextEdit *edit = currentEditor();
QKeyEvent *keyEvent = (QKeyEvent *)event;
@@ -309,7 +315,7 @@ bool Preview::eventFilter(QObject *target, QEvent *event)
void Preview::searchTextLine_textChanged(const QString & text)
{
- LOGDEB1(("search line text changed. text: '%s'\n", text.ascii()));
+ LOGDEB2(("search line text changed. text: '%s'\n", text.ascii()));
if (text.isEmpty()) {
m_dynSearchActive = false;
// nextButton->setEnabled(false);
@@ -331,6 +337,7 @@ void Preview::searchTextLine_textChanged(const QString & text)
PreviewTextEdit *Preview::currentEditor()
{
+ LOGDEB2(("Preview::currentEditor()\n"));
QWidget *tw = pvTab->currentPage();
PreviewTextEdit *edit = 0;
if (tw) {
@@ -347,8 +354,8 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
bool wordOnly)
{
LOGDEB(("Preview::doSearch: text [%s] txtlen %d next %d rev %d word %d\n",
- (const char *)_text.utf8(), _text.length(), int(next),
- int(reverse), int(wordOnly)));
+ (const char *)_text.utf8(), _text.length(), int(next),
+ int(reverse), int(wordOnly)));
QString text = _text;
bool matchCase = matchCheck->isChecked();
@@ -393,10 +400,11 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
LOGDEB(("Preview::doSearch: setting cursor to %d %d\n", ps, is));
edit->setCursorPosition(ps, is);
}
-
+ Chrono chron;
LOGDEB(("Preview::doSearch: first find call\n"));
bool found = edit->find(text, matchCase, wordOnly, !reverse, 0, 0);
- LOGDEB(("Preview::doSearch: first find call return\n"));
+ LOGDEB(("Preview::doSearch: first find call return: %.2f S\n",
+ chron.secs()));
// If not found, try to wrap around.
if (!found && next) {
LOGDEB(("Preview::doSearch: wrapping around\n"));
@@ -408,8 +416,10 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
mspara = msindex = 0;
}
LOGDEB(("Preview::doSearch: 2nd find call\n"));
+ chron.restart();
found = edit->find(text,matchCase, false, !reverse, &mspara, &msindex);
- LOGDEB(("Preview::doSearch: 2nd find call return\n"));
+ LOGDEB(("Preview::doSearch: 2nd find call return %.2f S\n",
+ chron.secs()));
}
if (found) {
@@ -424,17 +434,20 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
void Preview::nextPressed()
{
+ LOGDEB2(("PreviewTextEdit::nextPressed\n"));
doSearch(searchTextLine->text(), true, false);
}
void Preview::prevPressed()
{
+ LOGDEB2(("PreviewTextEdit::prevPressed\n"));
doSearch(searchTextLine->text(), true, true);
}
// Called when user clicks on tab
void Preview::currentChanged(QWidget * tw)
{
+ LOGDEB2(("PreviewTextEdit::currentChanged\n"));
PreviewTextEdit *edit =
dynamic_cast(tw->child("pvEdit"));
m_currentW = tw;
@@ -471,7 +484,7 @@ void Preview::currentChanged(QWidget * tw)
// qt version.
void Preview::selecChanged()
{
- LOGDEB1(("Selection changed\n"));
+ LOGDEB1(("Preview::selecChanged\n"));
if (!m_currentW)
return;
PreviewTextEdit *edit = (PreviewTextEdit*)m_currentW->child("pvEdit");
@@ -511,7 +524,7 @@ void Preview::textDoubleClicked(int, int)
void Preview::closeCurrentTab()
{
- LOGDEB(("Preview::closeCurrentTab: m_loading %d\n", m_loading));
+ LOGDEB1(("Preview::closeCurrentTab: m_loading %d\n", m_loading));
if (m_loading) {
CancelCheck::instance().setCancel();
return;
@@ -528,6 +541,7 @@ void Preview::closeCurrentTab()
PreviewTextEdit *Preview::addEditorTab()
{
+ LOGDEB1(("PreviewTextEdit::addEditorTab()\n"));
QWidget *anon = new QWidget((QWidget *)pvTab);
QVBoxLayout *anonLayout = new QVBoxLayout(anon, 1, 1, "anonLayout");
PreviewTextEdit *editor = new PreviewTextEdit(anon, "pvEdit", this);
@@ -541,6 +555,7 @@ PreviewTextEdit *Preview::addEditorTab()
void Preview::setCurTabProps(const Rcl::Doc &doc, int docnum)
{
+ LOGDEB1(("PreviewTextEdit::setCurTabProps\n"));
QString title;
map::const_iterator meta_it;
if ((meta_it = doc.meta.find(Rcl::Doc::keytt)) != doc.meta.end()
@@ -705,6 +720,11 @@ class LoadThread : public QThread {
}
};
+// 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
+
/* A thread to convert to rich text (mark search terms) */
class ToRichThread : public QThread {
string ∈
@@ -723,7 +743,7 @@ class ToRichThread : public QThread {
{
DebugLog::getdbl()->setloglevel(loglevel);
try {
- ptr.plaintorich(in, out, hdata);
+ ptr.plaintorich(in, out, hdata, CHUNKL);
} catch (CancelExcept) {
}
}
@@ -739,10 +759,6 @@ class WaiterThread : public QThread {
}
};
-#define CHUNKL 50*1000
-#ifndef MIN
-#define MIN(A,B) ((A)<(B)?(A):(B))
-#endif
class LoadGuard {
bool *m_bp;
public:
@@ -752,6 +768,7 @@ public:
bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
{
+ LOGDEB1(("PreviewTextEdit::loadDocInCurrentTab()\n"));
if (m_loading) {
LOGERR(("ALready loading\n"));
return false;
@@ -828,14 +845,36 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
// Final text is produced in chunks so that we can display the top
// while still inserting at bottom
list qrichlst;
+ PreviewTextEdit *editor = currentEditor();
+ editor->setText("");
+ editor->setTextFormat(Qt::RichText);
bool inputishtml = !fdoc.mimetype.compare("text/html");
+
+#if 0
+ // For testing qtextedit bugs...
+ highlightTerms = true;
+ const char *textlist[] =
+ {
+ "Du plain text avec un\n 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) {
+ QStyleSheetItem *item =
+ new QStyleSheetItem(editor->styleSheet(), "termtag" );
+ item->setColor(prefs.qtermcolor);
+ item->setFontWeight(QFont::Bold);
progress.setLabelText(tr("Creating preview text"));
qApp->processEvents();
+
if (inputishtml) {
LOGDEB1(("Preview: got html %s\n", fdoc.text.c_str()));
m_plaintorich.set_inputhtml(true);
} else {
+ LOGDEB1(("Preview: got plain %s\n", fdoc.text.c_str()));
m_plaintorich.set_inputhtml(false);
}
list richlst;
@@ -885,22 +924,14 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
if (inputishtml) {
qrichlst.push_back(qr);
} else {
+ editor->setTextFormat(Qt::PlainText);
for (int pos = 0; pos < (int)qr.length(); pos += l) {
l = MIN(CHUNKL, qr.length() - pos);
qrichlst.push_back(qr.mid(pos, l));
}
}
}
-
- // Load into editor
- PreviewTextEdit *editor = currentEditor();
- editor->setText("");
- if (highlightTerms) {
- QStyleSheetItem *item =
- new QStyleSheetItem(editor->styleSheet(), "termtag" );
- item->setColor(prefs.qtermcolor);
- item->setFontWeight(QFont::Bold);
- }
+#endif
prog = 2 * nsteps / 3;
progress.setLabelText(tr("Loading preview text into editor"));
@@ -969,6 +1000,7 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
RCLPOPUP *PreviewTextEdit::createPopupMenu(const QPoint&)
{
+ LOGDEB1(("PreviewTextEdit::createPopupMenu()\n"));
RCLPOPUP *popup = new RCLPOPUP(this);
if (!m_dspflds) {
popup->insertItem(tr("Show fields"), this, SLOT(toggleFields()));
@@ -982,7 +1014,7 @@ RCLPOPUP *PreviewTextEdit::createPopupMenu(const QPoint&)
// Either display document fields or main text
void PreviewTextEdit::toggleFields()
{
-// fprintf(stderr, "%s", (const char *)text().ascii());
+ LOGDEB1(("PreviewTextEdit::toggleFields()\n"));
// If currently displaying fields, switch to body text
if (m_dspflds) {
@@ -1010,6 +1042,7 @@ void PreviewTextEdit::toggleFields()
void PreviewTextEdit::print()
{
+ LOGDEB1(("PreviewTextEdit::print\n"));
if (!m_preview)
return;
diff --git a/src/qtgui/preview_w.h b/src/qtgui/preview_w.h
index 7de6b972..997b8cbb 100644
--- a/src/qtgui/preview_w.h
+++ b/src/qtgui/preview_w.h
@@ -98,7 +98,7 @@ public:
if (m_inputhtml) {
return snull;
} else {
- return string("");
+ return string("");
}
}
virtual string startMatch() {return string("");}
@@ -115,6 +115,10 @@ public:
virtual string startAnchor(int i) {
return string("";
}
+ virtual string endAnchor() {
+ return string("");
+ }
+ virtual string startChunk() { return "";}
};
class Preview : public QWidget {
diff --git a/src/query/plaintorich.cpp b/src/query/plaintorich.cpp
index 9e635688..d56351f9 100644
--- a/src/query/plaintorich.cpp
+++ b/src/query/plaintorich.cpp
@@ -327,6 +327,7 @@ bool PlainToRich::plaintorich(const string& in,
sterms += "\n";
}
LOGDEB0((" %s", sterms.c_str()));
+ LOGDEB2((" TEXT:[%s]\n", in.c_str()));
}
// Compute the positions for the query terms. We use the text
@@ -364,13 +365,19 @@ bool PlainToRich::plaintorich(const string& in,
// Input character iterator
Utf8Iter chariter(in);
- // State variable used to limit the number of consecutive empty lines
- int ateol = 0;
+
+ // State variable used to limit the number of consecutive empty lines,
+ // and convert all eol to '\n'
+ int eol = 0;
+ int hadcr = 0;
// Value for numbered anchors at each term match
int anchoridx = 1;
- // html state
+ // HTML state
bool intag = false, inparamvalue = false;
+ // My tag state
+ int inrcltag = 0;
+
unsigned int headend = 0;
if (m_inputhtml) {
headend = in.find("");
@@ -379,6 +386,7 @@ bool PlainToRich::plaintorich(const string& in,
if (headend != string::npos)
headend += 7;
}
+
for (string::size_type pos = 0; pos != string::npos; pos = chariter++) {
// Check from time to time if we need to stop
if ((pos & 0xfff) == 0) {
@@ -395,8 +403,9 @@ bool PlainToRich::plaintorich(const string& in,
*olit += startMatch();
}
anchoridx++;
+ inrcltag = 1;
} else if (ibyteidx == tPosIt->second) {
- // Output end or match region tags
+ // Output end of match region tags
if (!intag && ibyteidx > (int)headend) {
*olit += endMatch();
*olit += endAnchor();
@@ -405,60 +414,76 @@ bool PlainToRich::plaintorich(const string& in,
int crend = tPosIt->second;
while (tPosIt != cb.tboffs.end() && tPosIt->first < crend)
tPosIt++;
-
- // Maybe end this chunk, begin next. Don't do it on html
- // there is just no way to do it right (qtextedit cant grok
- // chunks cut in the middle of for example).
- if (!m_inputhtml && olit->size() > (unsigned int)chunksize) {
- out.push_back("");
- olit++;
- }
+ inrcltag = 0;
}
}
+
+ unsigned int car = *chariter;
+
+ if (car == '\n') {
+ if (!hadcr)
+ eol++;
+ hadcr = 0;
+ continue;
+ } else if (car == '\r') {
+ hadcr++;
+ eol++;
+ continue;
+ } else if (eol) {
+ // Do line break;
+ hadcr = 0;
+ if (eol > 2)
+ eol = 2;
+ while (eol) {
+ *olit += "\n";
+ eol--;
+ }
+ // Maybe end this chunk, begin next. Don't do it on html
+ // there is just no way to do it right (qtextedit cant grok
+ // chunks cut in the middle of for example).
+ if (!m_inputhtml && !inrcltag &&
+ olit->size() > (unsigned int)chunksize) {
+ out.push_back(string(startChunk()));
+ olit++;
+ }
+ }
+
+ switch (car) {
+ case '<':
+ if (m_inputhtml) {
+ if (!inparamvalue)
+ intag = true;
+ chariter.appendchartostring(*olit);
+ } else {
+ *olit += "<";
+ }
+ break;
+ case '>':
+ if (m_inputhtml) {
+ if (!inparamvalue)
+ intag = false;
+ }
+ chariter.appendchartostring(*olit);
+ break;
+ case '&':
+ if (m_inputhtml) {
+ chariter.appendchartostring(*olit);
+ } else {
+ *olit += "&";
+ }
+ break;
+ case '"':
+ if (m_inputhtml && intag) {
+ inparamvalue = !inparamvalue;
+ }
+ chariter.appendchartostring(*olit);
+ break;
+ default:
+ chariter.appendchartostring(*olit);
+ }
+
+ } // End chariter loop
- if (m_inputhtml) {
- switch (*chariter) {
- case '<':
- if (!inparamvalue)
- intag = true;
- break;
- case '>':
- if (!inparamvalue)
- intag = false;
- break;
- case '"':
- if (intag) {
- inparamvalue = !inparamvalue;
- }
- break;
- }
- chariter.appendchartostring(*olit);
- } else switch (*chariter) {
- case '\n':
- if (ateol < 2) {
- *olit += "
\n";
- ateol++;
- }
- break;
- case '\r':
- break;
- case '<':
- ateol = 0;
- *olit += "<";
- break;
- case '&':
- ateol = 0;
- *olit += "&";
- break;
- default:
- // We don't change the eol status for whitespace, want
- // a real line
- if (!(*chariter == ' ' || *chariter == '\t')) {
- ateol = 0;
- }
- chariter.appendchartostring(*olit);
- }
- }
#if 0
{
FILE *fp = fopen("/tmp/debugplaintorich", "a");
diff --git a/src/query/plaintorich.h b/src/query/plaintorich.h
index 63e9b361..9354dd1a 100644
--- a/src/query/plaintorich.h
+++ b/src/query/plaintorich.h
@@ -78,6 +78,7 @@ public:
virtual string endMatch() {return snull;}
virtual string startAnchor(int) {return snull;}
virtual string endAnchor() {return snull;}
+ virtual string startChunk() {return snull;}
protected:
static const string snull;
diff --git a/src/sampleconf/mimeconf b/src/sampleconf/mimeconf
index da4d59b1..8618472b 100644
--- a/src/sampleconf/mimeconf
+++ b/src/sampleconf/mimeconf
@@ -65,14 +65,14 @@ application/vnd.sun.xml.writer.global = exec rclsoff
application/vnd.sun.xml.writer.template = exec rclsoff
application/vnd.wordperfect = exec wpd2html;mimetype=text/html
application/x-abiword = exec rclabw
-application/x-awk = exec rcltext
+application/x-awk = internal
application/x-dvi = exec rcldvi
application/x-flac = exec rclflac
application/x-kword = exec rclkwd
application/x-lyx = exec rcllyx
-application/x-perl = exec rcltext
+application/x-perl = internal
application/x-scribus = exec rclscribus
-application/x-shellscript = exec rcltext
+application/x-shellscript = internal
application/x-tex = exec rcltex
application/x-chm = execm rclchm
application/zip = execm rclzip
@@ -88,15 +88,14 @@ text/calendar = execm rclics;mimetype=text/plain;charset=utf-8
text/html = internal
text/plain = internal
text/rtf = exec unrtf --nopict --html;charset=iso-8859-1;mimetype=text/html
-text/x-c = exec rcltext
-text/x-c++ = exec rcltext
+text/x-c = internal
text/x-gaim-log = exec rclgaim
text/x-html-sidux-man = exec rclsiduxman
text/x-mail = internal
text/x-man = exec rclman
text/x-purple-log = exec rclpurple
text/x-python = exec rclpython
-text/x-shellscript = exec rcltext
+text/x-shellscript = internal
## #############################################
# Icons to be used in the result list if required by gui config