finally got anchors to work. qt3

This commit is contained in:
dockes 2007-11-15 18:05:32 +00:00
parent c7f462c976
commit 8fc223425b
5 changed files with 156 additions and 107 deletions

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: plaintorich.cpp,v 1.29 2007-10-18 10:39:41 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: plaintorich.cpp,v 1.30 2007-11-15 18:05:32 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -309,24 +309,9 @@ string termAnchorName(int i)
return string(acname); return string(acname);
} }
#ifdef QT_SCROLL_TO_ANCHOR_BUG
// qtextedit scrolltoanchor(), which we would like to use to walk the
// search hit positions does not work well. So we mark the positions with
// a special string which we then use with the find() function for positionning
// We used to use some weird utf8 char for this, but this was displayed
// inconsistently depending of system, font, etc. We now use a good ole ctl
// char which doesnt' seem to cause any trouble. Wanted to use ^L, but can't
// be searched, so ^G
const char *firstTermBeacon = "\007";
#endif
static string termBeacon(int i) static string termBeacon(int i)
{ {
return string("<a name=\"") + termAnchorName(i) + "\">" return string("<a name=\"") + termAnchorName(i) + "\">";
#ifdef QT_SCROLL_TO_ANCHOR_BUG
+ firstTermBeacon
#endif
+ "</a>";
} }
@ -342,7 +327,7 @@ static string termBeacon(int i)
// caller will use the editor's find() function to position on it // caller will use the editor's find() function to position on it
bool plaintorich(const string& in, list<string>& out, bool plaintorich(const string& in, list<string>& out,
const HiliteData& hdata, const HiliteData& hdata,
bool noHeader, bool needBeacons, int chunksize) bool noHeader, int *lastAnchor, int chunksize)
{ {
Chrono chron; Chrono chron;
const vector<string>& terms(hdata.terms); const vector<string>& terms(hdata.terms);
@ -416,7 +401,7 @@ bool plaintorich(const string& in, list<string>& out,
if (tPosIt != tboffsend) { if (tPosIt != tboffsend) {
int ibyteidx = chariter.getBpos(); int ibyteidx = chariter.getBpos();
if (ibyteidx == tPosIt->first) { if (ibyteidx == tPosIt->first) {
if (needBeacons) if (lastAnchor)
*sit += termBeacon(anchoridx++); *sit += termBeacon(anchoridx++);
*sit += "<termtag>"; *sit += "<termtag>";
} else if (ibyteidx == tPosIt->second) { } else if (ibyteidx == tPosIt->second) {
@ -461,6 +446,8 @@ bool plaintorich(const string& in, list<string>& out,
chariter.appendchartostring(*sit); chariter.appendchartostring(*sit);
} }
} }
if (lastAnchor)
*lastAnchor = anchoridx - 1;
#if 0 #if 0
{ {
FILE *fp = fopen("/tmp/debugplaintorich", "a"); FILE *fp = fopen("/tmp/debugplaintorich", "a");

View File

@ -16,7 +16,7 @@
*/ */
#ifndef _PLAINTORICH_H_INCLUDED_ #ifndef _PLAINTORICH_H_INCLUDED_
#define _PLAINTORICH_H_INCLUDED_ #define _PLAINTORICH_H_INCLUDED_
/* @(#$Id: plaintorich.h,v 1.15 2007-10-18 10:39:41 dockes Exp $ (C) 2004 J.F.Dockes */ /* @(#$Id: plaintorich.h,v 1.16 2007-11-15 18:05:32 dockes Exp $ (C) 2004 J.F.Dockes */
#include <string> #include <string>
#include <list> #include <list>
@ -43,22 +43,15 @@ struct HiliteData {
* @param hdata terms and groups to be highlighted. These are * @param hdata terms and groups to be highlighted. These are
* lowercase and unaccented. * lowercase and unaccented.
* @param noHeader if true don't output header (<qt><title>...) * @param noHeader if true don't output header (<qt><title>...)
* @param needBeacons Need to navigate highlighted terms, mark them. * @param needBeacons Need to navigate highlighted terms, mark them,return last
*/ */
extern bool plaintorich(const string &in, list<string> &out, extern bool plaintorich(const string &in, list<string> &out,
const HiliteData& hdata, const HiliteData& hdata,
bool noHeader, bool noHeader,
bool needBeacons, int *needBeacons,
int chunksize = 50000 int chunksize = 50000
); );
extern string termAnchorName(int i); extern string termAnchorName(int i);
#define QT_SCROLL_TO_ANCHOR_BUG
#ifdef QT_SCROLL_TO_ANCHOR_BUG
// For some reason, can't get scrollToAnchor() to work. We use a special
// string as a beacon for the match area.
extern const char *firstTermBeacon;
#endif
#endif /* _PLAINTORICH_H_INCLUDED_ */ #endif /* _PLAINTORICH_H_INCLUDED_ */

View File

@ -1,5 +1,5 @@
#ifndef lint #ifndef lint
static char rcsid[] = "@(#$Id: preview_w.cpp,v 1.28 2007-10-18 10:39:41 dockes Exp $ (C) 2005 J.F.Dockes"; static char rcsid[] = "@(#$Id: preview_w.cpp,v 1.29 2007-11-15 18:05:32 dockes Exp $ (C) 2005 J.F.Dockes";
#endif #endif
/* /*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -69,6 +69,62 @@ using std::pair;
void Preview::init() void Preview::init()
{ {
setName("Preview");
setSizePolicy( QSizePolicy((QSizePolicy::SizeType)5,
(QSizePolicy::SizeType)5, 0, 0,
sizePolicy().hasHeightForWidth()));
QVBoxLayout* previewLayout =
new QVBoxLayout( this, 4, 6, "previewLayout");
pvTab = new QTabWidget(this, "pvTab");
// Create the first tab. Should be possible to use addEditorTab
// but this causes a pb with the sizeing
QWidget *unnamed = new QWidget(pvTab, "unnamed");
QVBoxLayout *unnamedLayout =
new QVBoxLayout(unnamed, 0, 6, "unnamedLayout");
QTextEditFixed *pvEdit = new QTextEditFixed(unnamed, "pvEdit");
pvEdit->setFocusPolicy(QTextEdit::WheelFocus);
pvEdit->setReadOnly(TRUE);
pvEdit->setUndoRedoEnabled(FALSE);
unnamedLayout->addWidget(pvEdit);
pvTab->insertTab(unnamed, QString::fromLatin1(""));
m_tabData.push_back(TabData(pvTab->currentPage()));
previewLayout->addWidget(pvTab);
// Create the buttons and entry field
QHBoxLayout *layout3 = new QHBoxLayout(0, 0, 6, "layout3");
searchLabel = new QLabel(this, "searchLabel");
layout3->addWidget(searchLabel);
searchTextLine = new QLineEdit(this, "searchTextLine");
layout3->addWidget(searchTextLine);
nextButton = new QPushButton(this, "nextButton");
nextButton->setEnabled(TRUE);
layout3->addWidget(nextButton);
prevButton = new QPushButton(this, "prevButton");
prevButton->setEnabled(TRUE);
layout3->addWidget(prevButton);
clearPB = new QPushButton(this, "clearPB");
clearPB->setEnabled(FALSE);
layout3->addWidget(clearPB);
matchCheck = new QCheckBox(this, "matchCheck");
layout3->addWidget(matchCheck);
previewLayout->addLayout(layout3);
resize(QSize(640, 480).expandedTo(minimumSizeHint()));
clearWState(WState_Polished);
// buddies
searchLabel->setBuddy(searchTextLine);
searchLabel->setText(tr("&Search for:"));
nextButton->setText(tr("&Next"));
prevButton->setText(tr("&Previous"));
clearPB->setText(tr("Clear"));
matchCheck->setText(tr("Match &Case"));
#if 0 #if 0
// Couldn't get a small button really in the corner. stays on the left of // Couldn't get a small button really in the corner. stays on the left of
// the button area and looks ugly // the button area and looks ugly
@ -93,7 +149,6 @@ void Preview::init()
m_dynSearchActive = false; m_dynSearchActive = false;
m_canBeep = true; m_canBeep = true;
m_tabData.push_back(TabData(pvTab->currentPage()));
m_currentW = 0; m_currentW = 0;
if (prefs.pvwidth > 100) { if (prefs.pvwidth > 100) {
resize(prefs.pvwidth, prefs.pvheight); resize(prefs.pvwidth, prefs.pvheight);
@ -102,6 +157,7 @@ void Preview::init()
currentChanged(pvTab->currentPage()); currentChanged(pvTab->currentPage());
m_justCreated = true; m_justCreated = true;
m_haveAnchors = false; m_haveAnchors = false;
m_curAnchor = 1;
} }
void Preview::closeEvent(QCloseEvent *e) void Preview::closeEvent(QCloseEvent *e)
@ -161,9 +217,9 @@ bool Preview::eventFilter(QObject *target, QEvent *event)
return QApplication::sendEvent(searchTextLine, event); return QApplication::sendEvent(searchTextLine, event);
} else { } else {
QWidget *tw = pvTab->currentPage(); QWidget *tw = pvTab->currentPage();
QTextEdit *e = 0; QTextEditFixed *e = 0;
if (tw) if (tw)
e = (QTextEdit *)tw->child("pvEdit"); e = (QTextEditFixed *)tw->child("pvEdit");
LOGDEB1(("Widget: %p, edit %p, target %p\n", tw, e, target)); LOGDEB1(("Widget: %p, edit %p, target %p\n", tw, e, target));
if (e && target == e) { if (e && target == e) {
if (keyEvent->key() == Qt::Key_Slash) { if (keyEvent->key() == Qt::Key_Slash) {
@ -201,17 +257,16 @@ void Preview::searchTextLine_textChanged(const QString & text)
} }
#if (QT_VERSION >= 0x040000) #if (QT_VERSION >= 0x040000)
#define QTextEdit Q3TextEdit
#define QProgressDialog Q3ProgressDialog #define QProgressDialog Q3ProgressDialog
#define QStyleSheetItem Q3StyleSheetItem #define QStyleSheetItem Q3StyleSheetItem
#endif #endif
QTextEdit *Preview::getCurrentEditor() QTextEditFixed *Preview::getCurrentEditor()
{ {
QWidget *tw = pvTab->currentPage(); QWidget *tw = pvTab->currentPage();
QTextEdit *edit = 0; QTextEditFixed *edit = 0;
if (tw) { if (tw) {
edit = (QTextEdit*)tw->child("pvEdit"); edit = (QTextEditFixed*)tw->child("pvEdit");
} }
return edit; return edit;
} }
@ -229,7 +284,7 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
QString text = _text; QString text = _text;
bool matchCase = matchCheck->isChecked(); bool matchCase = matchCheck->isChecked();
QTextEdit *edit = getCurrentEditor(); QTextEditFixed *edit = getCurrentEditor();
if (edit == 0) { if (edit == 0) {
// ?? // ??
return; return;
@ -238,12 +293,13 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse,
if (text.isEmpty()) { if (text.isEmpty()) {
if (m_haveAnchors == false) if (m_haveAnchors == false)
return; return;
#ifdef QT_SCROLL_TO_ANCHOR_BUG if (m_curAnchor == m_lastAnchor)
text = QString::fromUtf8(firstTermBeacon); m_curAnchor = 1;
matchCase = false; else
#else m_curAnchor++;
#error "Cycling without beacons needs coding" QString aname =
#endif QString::fromUtf8(termAnchorName(m_curAnchor).c_str());
edit->moveToAnchor(aname);
} }
// If next is false, the user added characters to the current // If next is false, the user added characters to the current
@ -339,7 +395,7 @@ void Preview::selecChanged()
LOGDEB1(("Selection changed\n")); LOGDEB1(("Selection changed\n"));
if (!m_currentW) if (!m_currentW)
return; return;
QTextEdit *edit = (QTextEdit *)m_currentW->child("pvEdit"); QTextEditFixed *edit = (QTextEditFixed*)m_currentW->child("pvEdit");
if (edit == 0) { if (edit == 0) {
LOGERR(("Editor child not found\n")); LOGERR(("Editor child not found\n"));
return; return;
@ -365,7 +421,7 @@ void Preview::textDoubleClicked(int, int)
LOGDEB2(("Preview::textDoubleClicked\n")); LOGDEB2(("Preview::textDoubleClicked\n"));
if (!m_currentW) if (!m_currentW)
return; return;
QTextEdit *edit = (QTextEdit *)m_currentW->child("pvEdit"); QTextEditFixed *edit = (QTextEditFixed *)m_currentW->child("pvEdit");
if (edit == 0) { if (edit == 0) {
LOGERR(("Editor child not found\n")); LOGERR(("Editor child not found\n"));
return; return;
@ -399,11 +455,11 @@ void Preview::closeCurrentTab()
} }
} }
QTextEdit *Preview::addEditorTab() QTextEditFixed *Preview::addEditorTab()
{ {
QWidget *anon = new QWidget((QWidget *)pvTab); QWidget *anon = new QWidget((QWidget *)pvTab);
QVBoxLayout *anonLayout = new QVBoxLayout(anon, 1, 1, "anonLayout"); QVBoxLayout *anonLayout = new QVBoxLayout(anon, 1, 1, "anonLayout");
QTextEdit *editor = new QTextEdit(anon, "pvEdit"); QTextEditFixed *editor = new QTextEditFixed(anon, "pvEdit");
editor->setReadOnly(TRUE); editor->setReadOnly(TRUE);
editor->setUndoRedoEnabled(FALSE ); editor->setUndoRedoEnabled(FALSE );
anonLayout->addWidget(editor); anonLayout->addWidget(editor);
@ -585,9 +641,11 @@ class ToRichThread : public QThread {
const HiliteData &hdata; const HiliteData &hdata;
list<string> &out; list<string> &out;
int loglevel; int loglevel;
int *lastanchor;
public: public:
ToRichThread(string &i, const HiliteData& hd, list<string> &o) ToRichThread(string &i, const HiliteData& hd, list<string> &o,
: in(i), hdata(hd), out(o) int *lsta)
: in(i), hdata(hd), out(o), lastanchor(lsta)
{ {
loglevel = DebugLog::getdbl()->getlevel(); loglevel = DebugLog::getdbl()->getlevel();
} }
@ -595,7 +653,7 @@ class ToRichThread : public QThread {
{ {
DebugLog::getdbl()->setloglevel(loglevel); DebugLog::getdbl()->setloglevel(loglevel);
try { try {
plaintorich(in, out, hdata, false, true); plaintorich(in, out, hdata, false, lastanchor);
} catch (CancelExcept) { } catch (CancelExcept) {
} }
} }
@ -712,7 +770,7 @@ bool Preview::loadFileInCurrentTab(string fn, size_t sz, const Rcl::Doc &idoc,
progress.setLabelText(tr("Creating preview text")); progress.setLabelText(tr("Creating preview text"));
qApp->processEvents(); qApp->processEvents();
list<string> richlst; list<string> richlst;
ToRichThread rthr(fdoc.text, m_hData, richlst); ToRichThread rthr(fdoc.text, m_hData, richlst, &m_lastAnchor);
rthr.start(); rthr.start();
for (;;prog++) { for (;;prog++) {
@ -760,7 +818,7 @@ bool Preview::loadFileInCurrentTab(string fn, size_t sz, const Rcl::Doc &idoc,
} }
// Load into editor // Load into editor
QTextEdit *editor = getCurrentEditor(); QTextEditFixed *editor = getCurrentEditor();
editor->setText(""); editor->setText("");
if (highlightTerms) { if (highlightTerms) {
QStyleSheetItem *item = QStyleSheetItem *item =
@ -777,8 +835,6 @@ bool Preview::loadFileInCurrentTab(string fn, size_t sz, const Rcl::Doc &idoc,
it != qrichlst.end(); it++, prog++, instep++) { it != qrichlst.end(); it++, prog++, instep++) {
progress.setProgress(prog , prog <= nsteps-1 ? nsteps : prog+1); progress.setProgress(prog , prog <= nsteps-1 ? nsteps : prog+1);
qApp->processEvents(); qApp->processEvents();
if (it->find(QString::fromUtf8(firstTermBeacon)) != -1)
m_haveAnchors = true;
editor->append(*it); editor->append(*it);
@ -795,9 +851,9 @@ bool Preview::loadFileInCurrentTab(string fn, size_t sz, const Rcl::Doc &idoc,
} }
} }
progress.close(); progress.close();
m_haveAnchors = m_lastAnchor != 0;
if (searchTextLine->text().length() != 0) { if (searchTextLine->text().length() != 0) {
// If there is a current search string, perform the search // If there is a current search string, perform the search
m_canBeep = true; m_canBeep = true;
@ -806,26 +862,9 @@ bool Preview::loadFileInCurrentTab(string fn, size_t sz, const Rcl::Doc &idoc,
// Position to the first query term // Position to the first query term
if (m_haveAnchors) { if (m_haveAnchors) {
QString aname = QString::fromUtf8(termAnchorName(1).c_str()); QString aname = QString::fromUtf8(termAnchorName(1).c_str());
LOGDEB2(("Call scrolltoanchor(%s)\n", (const char *)aname.utf8())); LOGDEB2(("Call movetoanchor(%s)\n", (const char *)aname.utf8()));
editor->scrollToAnchor(aname); editor->moveToAnchor(aname);
m_curAnchor = 1;
#if (QT_VERSION < 0x040000)
// The q3textedit version of te::find() is slow to the point of
// being unusable (plus it does not always work). So we
// don't position to the first term automatically, the
// user can still use the search function in the preview
// window to do it
#ifdef QT_SCROLL_TO_ANCHOR_BUG
bool ocanbeep = m_canBeep;
m_canBeep = false;
QString empty;
// Calling doSearch() with an empty string will look for
// the first occurrence of a search term`
// doSearch(_text, next, reverse, wordOnly)
doSearch(empty, true, false, false);
m_canBeep = ocanbeep;
#endif
#endif // (QT_VERSION < 0x040000)
} }
} }

View File

@ -1,6 +1,6 @@
#ifndef _PREVIEW_W_H_INCLUDED_ #ifndef _PREVIEW_W_H_INCLUDED_
#define _PREVIEW_W_H_INCLUDED_ #define _PREVIEW_W_H_INCLUDED_
/* @(#$Id: preview_w.h,v 1.15 2007-07-20 14:43:21 dockes Exp $ (C) 2006 J.F.Dockes */ /* @(#$Id: preview_w.h,v 1.16 2007-11-15 18:05:32 dockes Exp $ (C) 2006 J.F.Dockes */
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,15 +22,54 @@
#include <qwidget.h> #include <qwidget.h>
#include "rcldb.h" #include "rcldb.h"
#if (QT_VERSION < 0x040000)
#include "preview.h"
#else
#include "ui_preview.h"
#define QTextEdit Q3TextEdit
#endif
#include "refcntr.h" #include "refcntr.h"
#include "plaintorich.h" #include "plaintorich.h"
class QTabWidget;
class QLabel;
class QLineEdit;
class QPushButton;
class QCheckBox;
class QTextEditFixed;
#include <qtextedit.h>
#include <private/qrichtext_p.h>
class QTextEditFixed : public QTextEdit {
Q_OBJECT
public:
QTextEditFixed( QWidget* parent=0, const char* name=0 )
: QTextEdit(parent, name)
{}
void moveToAnchor(const QString& name)
{
if (name.isEmpty())
return;
sync();
QTextCursor l_cursor(document());
QTextParagraph* last = document()->lastParagraph();
for (;;) {
QTextStringChar* c = l_cursor.paragraph()->at(l_cursor.index());
if(c->isAnchor()) {
QString a = c->anchorName();
fprintf(stderr, "QTextEdit::scrollToAnchor: anchor nm [%s]\n",
(const char *)a.ascii());
if ( a == name ||
(a.contains( '#' ) &&
QStringList::split('#', a).contains(name))) {
*(textCursor()) = l_cursor;
ensureCursorVisible();
break;
}
}
if (l_cursor.paragraph() == last && l_cursor.atParagEnd())
break;
l_cursor.gotoNextLetter();
}
}
};
// We keep a list of data associated to each tab // We keep a list of data associated to each tab
class TabData { class TabData {
public: public:
@ -44,36 +83,18 @@ class TabData {
{} {}
}; };
class QTextEdit; class Preview : public QWidget {
//MOC_SKIP_BEGIN
#if QT_VERSION < 0x040000
class DummyPreviewBase : public PreviewBase
{
public: DummyPreviewBase(QWidget* parent = 0) : PreviewBase(parent) {}
};
#else
class DummyPreviewBase : public QWidget, public Ui::PreviewBase
{
public: DummyPreviewBase(QWidget* parent):QWidget(parent){setupUi(this);}
};
#endif
//MOC_SKIP_END
class Preview : public DummyPreviewBase
{
Q_OBJECT Q_OBJECT
public: public:
Preview(int sid, // Search Id Preview(int sid, // Search Id
const HiliteData& hdata) // Search terms etc. for highlighting const HiliteData& hdata) // Search terms etc. for highlighting
: DummyPreviewBase(0) : QWidget(0), m_searchId(sid), m_hData(hdata)
{ {
init(); init();
m_searchId = sid;
m_hData = hdata;
} }
~Preview(){} ~Preview(){}
virtual void closeEvent(QCloseEvent *e ); virtual void closeEvent(QCloseEvent *e );
@ -114,12 +135,22 @@ private:
HiliteData m_hData; HiliteData m_hData;
bool m_justCreated; // First tab create is different bool m_justCreated; // First tab create is different
bool m_haveAnchors; // Search terms are marked in text bool m_haveAnchors; // Search terms are marked in text
int m_lastAnchor; // Number of last anchor. Then rewind to 1
int m_curAnchor;
QTabWidget* pvTab;
QLabel* searchLabel;
QLineEdit* searchTextLine;
QPushButton* nextButton;
QPushButton* prevButton;
QPushButton* clearPB;
QCheckBox* matchCheck;
void init(); void init();
virtual void setCurTabProps(const string& fn, const Rcl::Doc& doc, virtual void setCurTabProps(const string& fn, const Rcl::Doc& doc,
int docnum); int docnum);
virtual QTextEdit *getCurrentEditor(); virtual QTextEditFixed *getCurrentEditor();
virtual QTextEdit *addEditorTab(); virtual QTextEditFixed *addEditorTab();
virtual bool loadFileInCurrentTab(string fn, size_t sz, virtual bool loadFileInCurrentTab(string fn, size_t sz,
const Rcl::Doc& idoc, int dnm); const Rcl::Doc& idoc, int dnm);
TabData *tabDataForCurrent(); // Return auxiliary data pointer for cur tab TabData *tabDataForCurrent(); // Return auxiliary data pointer for cur tab

View File

@ -39,7 +39,6 @@ SOURCES += \
FORMS = \ FORMS = \
advsearch.ui \ advsearch.ui \
spell.ui \ spell.ui \
preview.ui \
rclmain.ui \ rclmain.ui \
sort.ui \ sort.ui \
ssearchb.ui \ ssearchb.ui \