revamped history feature to be udi-based while supporting old format
This commit is contained in:
@@ -25,6 +25,84 @@ static char rcsid[] = "@(#$Id: docseqhist.cpp,v 1.4 2008-09-29 08:59:20 dockes E
|
||||
#include "rcldb.h"
|
||||
#include "fileudi.h"
|
||||
#include "internfile.h"
|
||||
#include "base64.h"
|
||||
#include "debuglog.h"
|
||||
#include "smallut.h"
|
||||
|
||||
// Encode document history entry:
|
||||
// U + Unix time + base64 of udi
|
||||
// The U distinguishes udi-based entries from older fn+ipath ones
|
||||
bool RclDHistoryEntry::encode(string& value)
|
||||
{
|
||||
char chartime[20];
|
||||
sprintf(chartime, "%ld", unixtime);
|
||||
string budi;
|
||||
base64_encode(udi, budi);
|
||||
value = string("U ") + string(chartime) + " " + budi;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decode. We support historical entries which were like "time b64fn [b64ipath]"
|
||||
// Current entry format is "U time b64udi"
|
||||
bool RclDHistoryEntry::decode(const string &value)
|
||||
{
|
||||
list<string> vall;
|
||||
stringToStrings(value, vall);
|
||||
|
||||
list<string>::const_iterator it = vall.begin();
|
||||
udi.erase();
|
||||
string fn, ipath;
|
||||
switch (vall.size()) {
|
||||
case 2:
|
||||
// Old fn+ipath, null ipath case
|
||||
unixtime = atol((*it++).c_str());
|
||||
base64_decode(*it++, fn);
|
||||
break;
|
||||
case 3:
|
||||
if (!it->compare("U")) {
|
||||
// New udi-based entry
|
||||
it++;
|
||||
unixtime = atol((*it++).c_str());
|
||||
base64_decode(*it++, udi);
|
||||
} else {
|
||||
// Old fn + ipath. We happen to know how to build an udi
|
||||
unixtime = atol((*it++).c_str());
|
||||
base64_decode(*it++, fn);
|
||||
base64_decode(*it, ipath);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fn.empty()) {
|
||||
// Old style entry found, make an udi, using the fs udi maker
|
||||
make_udi(fn, ipath, udi);
|
||||
}
|
||||
LOGDEB(("RclDHistoryEntry::decode: udi [%s]\n", udi.c_str()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RclDHistoryEntry::equal(const DynConfEntry& other)
|
||||
{
|
||||
const RclDHistoryEntry& e = dynamic_cast<const RclDHistoryEntry&>(other);
|
||||
return e.udi == udi;
|
||||
}
|
||||
|
||||
bool historyEnterDoc(RclDynConf *dncf, const string& udi)
|
||||
{
|
||||
LOGDEB(("historyEnterDoc: [%s] into %s\n",
|
||||
udi.c_str(), dncf->getFilename().c_str()));
|
||||
RclDHistoryEntry ne(time(0), udi);
|
||||
RclDHistoryEntry scratch;
|
||||
return dncf->insertNew(docHistSubKey, ne, scratch, 200);
|
||||
}
|
||||
|
||||
list<RclDHistoryEntry> getDocHistory(RclDynConf* dncf)
|
||||
{
|
||||
return dncf->getList<RclDHistoryEntry>(docHistSubKey);
|
||||
}
|
||||
|
||||
|
||||
bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh)
|
||||
{
|
||||
@@ -32,7 +110,7 @@ bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh)
|
||||
if (!m_hist)
|
||||
return false;
|
||||
if (m_hlist.empty())
|
||||
m_hlist = m_hist->getDocHistory();
|
||||
m_hlist = getDocHistory(m_hist);
|
||||
|
||||
if (num < 0 || num >= (int)m_hlist.size())
|
||||
return false;
|
||||
@@ -48,7 +126,8 @@ bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh)
|
||||
while (skip--)
|
||||
m_it++;
|
||||
if (sh) {
|
||||
if (m_prevtime < 0 || abs (float(m_prevtime) - float(m_it->unixtime)) > 86400) {
|
||||
if (m_prevtime < 0 ||
|
||||
abs (float(m_prevtime) - float(m_it->unixtime)) > 86400) {
|
||||
m_prevtime = m_it->unixtime;
|
||||
time_t t = (time_t)(m_it->unixtime);
|
||||
*sh = string(ctime(&t));
|
||||
@@ -57,12 +136,10 @@ bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh)
|
||||
} else
|
||||
sh->erase();
|
||||
}
|
||||
string udi;
|
||||
make_udi(m_it->fn, m_it->ipath, udi);
|
||||
bool ret = m_db->getDoc(udi, doc);
|
||||
bool ret = m_db->getDoc(m_it->udi, doc);
|
||||
if (!ret) {
|
||||
doc.url = string("file://") + m_it->fn;
|
||||
doc.ipath = m_it->ipath;
|
||||
doc.url = "UNKNOWN";
|
||||
doc.ipath = "";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -79,6 +156,6 @@ bool DocSequenceHistory::getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc)
|
||||
int DocSequenceHistory::getResCnt()
|
||||
{
|
||||
if (m_hlist.empty())
|
||||
m_hlist = m_hist->getDocHistory();
|
||||
m_hlist = getDocHistory(m_hist);
|
||||
return m_hlist.size();
|
||||
}
|
||||
|
||||
+19
-3
@@ -19,18 +19,32 @@
|
||||
/* @(#$Id: docseqhist.h,v 1.3 2008-09-29 08:59:20 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
|
||||
#include "docseq.h"
|
||||
#include "history.h"
|
||||
#include "dynconf.h"
|
||||
|
||||
namespace Rcl {
|
||||
class Db;
|
||||
}
|
||||
|
||||
/** DynConf Document history entry */
|
||||
class RclDHistoryEntry : public DynConfEntry {
|
||||
public:
|
||||
RclDHistoryEntry() : unixtime(0) {}
|
||||
RclDHistoryEntry(long t, const string& u)
|
||||
: unixtime(t), udi(u) {}
|
||||
virtual ~RclDHistoryEntry() {}
|
||||
virtual bool decode(const string &value);
|
||||
virtual bool encode(string& value);
|
||||
virtual bool equal(const DynConfEntry& other);
|
||||
long unixtime;
|
||||
string udi;
|
||||
};
|
||||
|
||||
/** A DocSequence coming from the history file.
|
||||
* History is kept as a list of urls. This queries the db to fetch
|
||||
* metadata for an url key */
|
||||
class DocSequenceHistory : public DocSequence {
|
||||
public:
|
||||
DocSequenceHistory(Rcl::Db *d, RclHistory *h, const string &t)
|
||||
DocSequenceHistory(Rcl::Db *d, RclDynConf *h, const string &t)
|
||||
: DocSequence(t), m_db(d), m_hist(h), m_prevnum(-1), m_prevtime(-1) {}
|
||||
virtual ~DocSequenceHistory() {}
|
||||
|
||||
@@ -41,7 +55,7 @@ class DocSequenceHistory : public DocSequence {
|
||||
void setDescription(const string& desc) {m_description = desc;}
|
||||
private:
|
||||
Rcl::Db *m_db;
|
||||
RclHistory *m_hist;
|
||||
RclDynConf *m_hist;
|
||||
int m_prevnum;
|
||||
long m_prevtime;
|
||||
string m_description; // This is just an nls translated 'doc history'
|
||||
@@ -49,4 +63,6 @@ class DocSequenceHistory : public DocSequence {
|
||||
list<RclDHistoryEntry>::const_iterator m_it;
|
||||
};
|
||||
|
||||
extern bool historyEnterDoc(RclDynConf *dncf, const string& udi);
|
||||
|
||||
#endif /* _DOCSEQ_H_INCLUDED_ */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: history.cpp,v 1.9 2007-12-13 06:58:21 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: dynconf.cpp,v 1.9 2007-12-13 06:58:21 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
#endif
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,7 +23,7 @@ static char rcsid[] = "@(#$Id: history.cpp,v 1.9 2007-12-13 06:58:21 dockes Exp
|
||||
#include <time.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "history.h"
|
||||
#include "dynconf.h"
|
||||
#include "base64.h"
|
||||
#include "smallut.h"
|
||||
#include "debuglog.h"
|
||||
@@ -32,63 +32,20 @@ static char rcsid[] = "@(#$Id: history.cpp,v 1.9 2007-12-13 06:58:21 dockes Exp
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
|
||||
// Encode/decode document history entry: Unix time + base64 of fn +
|
||||
// base64 of ipath separated by a space. If ipath is not set, there
|
||||
// are only 2 parts
|
||||
bool RclDHistoryEntry::encode(string& value)
|
||||
{
|
||||
char chartime[20];
|
||||
sprintf(chartime, "%ld", unixtime);
|
||||
string bfn, bipath;
|
||||
base64_encode(fn, bfn);
|
||||
base64_encode(ipath, bipath);
|
||||
value = string(chartime) + " " + bfn + " " + bipath;
|
||||
return true;
|
||||
}
|
||||
bool RclDHistoryEntry::decode(const string &value)
|
||||
{
|
||||
list<string> vall;
|
||||
stringToStrings(value, vall);
|
||||
list<string>::const_iterator it1 = vall.begin();
|
||||
if (vall.size() < 2)
|
||||
return false;
|
||||
unixtime = atol((*it1++).c_str());
|
||||
base64_decode(*it1++, fn);
|
||||
if (vall.size() == 3)
|
||||
base64_decode(*it1, ipath);
|
||||
else
|
||||
ipath.erase();
|
||||
return true;
|
||||
}
|
||||
bool RclDHistoryEntry::equal(const HistoryEntry& other)
|
||||
{
|
||||
const RclDHistoryEntry& e = dynamic_cast<const RclDHistoryEntry&>(other);
|
||||
return e.fn == fn && e.ipath == ipath;
|
||||
}
|
||||
// Well known keys for history and external indexes.
|
||||
const string docHistSubKey = "docs";
|
||||
const string allEdbsSk = "allExtDbs";
|
||||
const string actEdbsSk = "actExtDbs";
|
||||
|
||||
|
||||
// Encode/decode simple string. base64 used to avoid problems with
|
||||
// strange chars
|
||||
bool RclSListEntry::encode(string& enc)
|
||||
// @param sk section this is for
|
||||
// @param n new entry
|
||||
// @param s a scratch entry used for decoding and comparisons.
|
||||
// This avoids templating this routine for the actual entry type.
|
||||
bool RclDynConf::insertNew(const string &sk, DynConfEntry &n, DynConfEntry &s,
|
||||
int maxlen)
|
||||
{
|
||||
base64_encode(value, enc);
|
||||
return true;
|
||||
}
|
||||
bool RclSListEntry::decode(const string &enc)
|
||||
{
|
||||
base64_decode(enc, value);
|
||||
return true;
|
||||
}
|
||||
bool RclSListEntry::equal(const HistoryEntry& other)
|
||||
{
|
||||
const RclSListEntry& e = dynamic_cast<const RclSListEntry&>(other);
|
||||
return e.value == value;
|
||||
}
|
||||
|
||||
bool RclHistory::insertNew(const string &sk, HistoryEntry &n, HistoryEntry &s)
|
||||
{
|
||||
// Is this doc already in history ? If it is we remove the old entry
|
||||
// Is this doc already in list ? If it is we remove the old entry
|
||||
list<string> names = m_data.getNames(sk);
|
||||
list<string>::const_iterator it;
|
||||
bool changed = false;
|
||||
@@ -111,13 +68,13 @@ bool RclHistory::insertNew(const string &sk, HistoryEntry &n, HistoryEntry &s)
|
||||
if (changed)
|
||||
names = m_data.getNames(sk);
|
||||
|
||||
// How many do we have
|
||||
if (names.size() >= m_mlen) {
|
||||
// Need to prune ?
|
||||
if (maxlen > 0 && names.size() >= (unsigned int)maxlen) {
|
||||
// Need to erase entries until we're back to size. Note that
|
||||
// we don't ever reset numbers. Problems will arise when
|
||||
// history is 4 billion entries old
|
||||
it = names.begin();
|
||||
for (unsigned int i = 0; i < names.size() - m_mlen + 1; i++, it++) {
|
||||
for (unsigned int i = 0; i < names.size() - maxlen + 1; i++, it++) {
|
||||
m_data.erase(*it, sk);
|
||||
}
|
||||
}
|
||||
@@ -137,12 +94,10 @@ bool RclHistory::insertNew(const string &sk, HistoryEntry &n, HistoryEntry &s)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool RclHistory::eraseAll(const string &sk)
|
||||
bool RclDynConf::eraseAll(const string &sk)
|
||||
{
|
||||
// Is this doc already in history ? If it is we remove the old entry
|
||||
list<string> names = m_data.getNames(sk);
|
||||
list<string>::const_iterator it;
|
||||
for (it = names.begin(); it != names.end(); it++) {
|
||||
@@ -150,31 +105,36 @@ bool RclHistory::eraseAll(const string &sk)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool RclHistory::truncate(const string &sk, unsigned int n)
|
||||
|
||||
|
||||
// Generic string list specialization ///////////////////////////////////
|
||||
|
||||
// Encode/decode simple string. base64 used to avoid problems with
|
||||
// strange chars
|
||||
bool RclSListEntry::encode(string& enc)
|
||||
{
|
||||
// Is this doc already in history ? If it is we remove the old entry
|
||||
list<string> names = m_data.getNames(sk);
|
||||
if (names.size() <= n)
|
||||
return true;
|
||||
unsigned int i = 0;
|
||||
for (list<string>::const_iterator it = names.begin();
|
||||
it != names.end(); it++, i++) {
|
||||
if (i >= n)
|
||||
m_data.erase(*it, sk);
|
||||
}
|
||||
base64_encode(value, enc);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RclHistory::enterString(const string sk, const string value)
|
||||
bool RclSListEntry::decode(const string &enc)
|
||||
{
|
||||
base64_decode(enc, value);
|
||||
return true;
|
||||
}
|
||||
bool RclSListEntry::equal(const DynConfEntry& other)
|
||||
{
|
||||
const RclSListEntry& e = dynamic_cast<const RclSListEntry&>(other);
|
||||
return e.value == value;
|
||||
}
|
||||
bool RclDynConf::enterString(const string sk, const string value, int maxlen)
|
||||
{
|
||||
RclSListEntry ne(value);
|
||||
RclSListEntry scratch;
|
||||
return insertNew(sk, ne, scratch);
|
||||
return insertNew(sk, ne, scratch, maxlen);
|
||||
}
|
||||
list<string> RclHistory::getStringList(const string sk)
|
||||
list<string> RclDynConf::getStringList(const string sk)
|
||||
{
|
||||
list<RclSListEntry> el = getHistory<RclSListEntry>(sk);
|
||||
list<RclSListEntry> el = getList<RclSListEntry>(sk);
|
||||
list<string> sl;
|
||||
for (list<RclSListEntry>::const_iterator it = el.begin();
|
||||
it != el.end(); it++)
|
||||
@@ -182,26 +142,8 @@ list<string> RclHistory::getStringList(const string sk)
|
||||
return sl;
|
||||
}
|
||||
|
||||
string RclHistory::docSubkey = "docs";
|
||||
|
||||
/// *************** History entries specific methods
|
||||
bool RclHistory::enterDoc(const string fn, const string ipath)
|
||||
{
|
||||
LOGDEB(("RclDHistory::enterDoc: [%s] [%s] into %s\n",
|
||||
fn.c_str(), ipath.c_str(), m_data.getFilename().c_str()));
|
||||
RclDHistoryEntry ne(time(0), fn, ipath);
|
||||
RclDHistoryEntry scratch;
|
||||
return insertNew(docSubkey, ne, scratch);
|
||||
}
|
||||
|
||||
list<RclDHistoryEntry> RclHistory::getDocHistory()
|
||||
{
|
||||
return getHistory<RclDHistoryEntry>(docSubkey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
@@ -216,7 +158,7 @@ static string thisprog;
|
||||
|
||||
static string usage =
|
||||
"trhist [opts] <filename>\n"
|
||||
" [-s <subkey>]: specify subkey (default: RclHistory::docSubkey)\n"
|
||||
" [-s <subkey>]: specify subkey (default: RclDynConf::docHistSubKey)\n"
|
||||
" [-e] : erase all\n"
|
||||
" [-a <string>] enter string (needs -s, no good for history entries\n"
|
||||
"\n"
|
||||
@@ -236,7 +178,7 @@ static int op_flags;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
string sk = RclHistory::docSubkey;
|
||||
string sk = "docs";
|
||||
string value;
|
||||
|
||||
thisprog = argv[0];
|
||||
@@ -264,7 +206,7 @@ int main(int argc, char **argv)
|
||||
Usage();
|
||||
string filename = *argv++;argc--;
|
||||
|
||||
RclHistory hist(filename, 5);
|
||||
RclDynConf hist(filename, 5);
|
||||
DebugLog::getdbl()->setloglevel(DEBDEB1);
|
||||
DebugLog::setfilename("stderr");
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 _DYNCONF_H_INCLUDED_
|
||||
#define _DYNCONF_H_INCLUDED_
|
||||
/* @(#$Id: dynconf.h,v 1.7 2007-06-20 13:16:11 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
|
||||
/**
|
||||
* Dynamic configuration storage
|
||||
*
|
||||
* This used to be called "history" because of the initial usage.
|
||||
* Used to store some parameters which would fit neither in recoll.conf,
|
||||
* basically because they change a lot, nor in the QT preferences file, mostly
|
||||
* because they are specific to a configuration directory.
|
||||
* Examples:
|
||||
* - History of documents selected for preview
|
||||
* - Active and inactive external databases (depend on the
|
||||
* configuration directory)
|
||||
* - ...
|
||||
*
|
||||
* The storage is performed in a ConfSimple file, with subkeys and
|
||||
* encodings which depend on the data stored. Under each section, the keys
|
||||
* are sequential numeric, so this basically manages a set of lists.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
#include "conftree.h"
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
// Entry interface.
|
||||
class DynConfEntry {
|
||||
public:
|
||||
virtual ~DynConfEntry() {}
|
||||
virtual bool decode(const string &value) = 0;
|
||||
virtual bool encode(string& value) = 0;
|
||||
virtual bool equal(const DynConfEntry &other) = 0;
|
||||
};
|
||||
|
||||
|
||||
/** String storage generic object */
|
||||
class RclSListEntry : public DynConfEntry {
|
||||
public:
|
||||
RclSListEntry() {}
|
||||
RclSListEntry(const string& v) : value(v) {}
|
||||
virtual ~RclSListEntry() {}
|
||||
virtual bool decode(const string &enc);
|
||||
virtual bool encode(string& enc);
|
||||
virtual bool equal(const DynConfEntry& other);
|
||||
|
||||
string value;
|
||||
};
|
||||
|
||||
/** The dynamic configuration class */
|
||||
class RclDynConf {
|
||||
public:
|
||||
RclDynConf(const string &fn)
|
||||
: m_data(fn.c_str()) {}
|
||||
bool ok() {return m_data.getStatus() == ConfSimple::STATUS_RW;}
|
||||
string getFilename() {return m_data.getFilename();}
|
||||
|
||||
// Generic methods
|
||||
bool eraseAll(const string& sk);
|
||||
bool insertNew(const string& sk, DynConfEntry &n, DynConfEntry &s,
|
||||
int maxlen = -1);
|
||||
template<typename Tp> list<Tp> getList(const string& sk);
|
||||
|
||||
// Specialized methods for simple string lists, designated by the
|
||||
// subkey value
|
||||
bool enterString(const string sk, const string value, int maxlen = -1);
|
||||
list<string> getStringList(const string sk);
|
||||
|
||||
private:
|
||||
unsigned int m_mlen;
|
||||
ConfSimple m_data;
|
||||
|
||||
};
|
||||
|
||||
template<typename Tp> list<Tp> RclDynConf::getList(const string &sk)
|
||||
{
|
||||
list<Tp> mlist;
|
||||
Tp entry;
|
||||
list<string> names = m_data.getNames(sk);
|
||||
for (list<string>::const_iterator it = names.begin();
|
||||
it != names.end(); it++) {
|
||||
string value;
|
||||
if (m_data.get(*it, value, sk)) {
|
||||
if (!entry.decode(value))
|
||||
continue;
|
||||
mlist.push_front(entry);
|
||||
}
|
||||
}
|
||||
return mlist;
|
||||
}
|
||||
|
||||
// Defined subkeys. Values in dynconf.cpp
|
||||
// History
|
||||
extern const string docHistSubKey;
|
||||
// All external indexes
|
||||
extern const string allEdbsSk;
|
||||
// Active external indexes
|
||||
extern const string actEdbsSk;
|
||||
|
||||
#endif /* _DYNCONF_H_INCLUDED_ */
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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 _HISTORY_H_INCLUDED_
|
||||
#define _HISTORY_H_INCLUDED_
|
||||
/* @(#$Id: history.h,v 1.7 2007-06-20 13:16:11 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
|
||||
/**
|
||||
* Dynamic configuration storage
|
||||
*
|
||||
* The term "history" is a misnomer as this code is now used to save
|
||||
* all dynamic parameters except those that are stored in the global
|
||||
* recollrc QT preferences file. Examples:
|
||||
* - History of documents selected for preview
|
||||
* - Active and inactive external databases (these should depend on the
|
||||
* configuration directory and cant be stored in recollrc).
|
||||
* - ...
|
||||
*
|
||||
* The storage is performed in a ConSimple file, with subkeys and
|
||||
* encodings which depend on the data stored.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
#include "conftree.h"
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
class HistoryEntry {
|
||||
public:
|
||||
virtual ~HistoryEntry() {}
|
||||
virtual bool decode(const string &value) = 0;
|
||||
virtual bool encode(string& value) = 0;
|
||||
virtual bool equal(const HistoryEntry &other) = 0;
|
||||
};
|
||||
|
||||
|
||||
/** Document history entry */
|
||||
class RclDHistoryEntry : public HistoryEntry {
|
||||
public:
|
||||
RclDHistoryEntry() : unixtime(0) {}
|
||||
RclDHistoryEntry(long t, const string& f, const string& i)
|
||||
: unixtime(t), fn(f), ipath(i) {}
|
||||
virtual ~RclDHistoryEntry() {}
|
||||
virtual bool decode(const string &value);
|
||||
virtual bool encode(string& value);
|
||||
virtual bool equal(const HistoryEntry& other);
|
||||
long unixtime;
|
||||
string fn;
|
||||
string ipath;
|
||||
};
|
||||
|
||||
|
||||
/** String storage generic object */
|
||||
class RclSListEntry : public HistoryEntry {
|
||||
public:
|
||||
RclSListEntry() {}
|
||||
RclSListEntry(const string& v) : value(v) {}
|
||||
virtual ~RclSListEntry() {}
|
||||
virtual bool decode(const string &enc);
|
||||
virtual bool encode(string& enc);
|
||||
virtual bool equal(const HistoryEntry& other);
|
||||
|
||||
string value;
|
||||
};
|
||||
|
||||
/**
|
||||
* The history class. This uses a ConfSimple for storage, and should be
|
||||
* renamed something like dynconf, as it is used to stored quite a few
|
||||
* things beyond doc history: all dynamic configuration parameters that are
|
||||
* not suitable for QT settings because they are specific to a RECOLL_CONFDIR
|
||||
*/
|
||||
class RclHistory {
|
||||
public:
|
||||
RclHistory(const string &fn, unsigned int maxsize=100)
|
||||
: m_mlen(maxsize), m_data(fn.c_str()) {}
|
||||
bool ok() {return m_data.getStatus() == ConfSimple::STATUS_RW;}
|
||||
|
||||
// Specific methods for history entries. These are for convenience, they
|
||||
// just call regular methods with key RclHistory::docSubkey;
|
||||
bool enterDoc(const string fn, const string ipath);
|
||||
list<RclDHistoryEntry> getDocHistory();
|
||||
|
||||
// Generic methods used for string lists, designated by the subkey value
|
||||
bool enterString(const string sk, const string value);
|
||||
list<string> getStringList(const string sk);
|
||||
bool eraseAll(const string& sk);
|
||||
bool truncate(const string& sk, unsigned int n);
|
||||
|
||||
static string docSubkey;
|
||||
|
||||
private:
|
||||
unsigned int m_mlen;
|
||||
ConfSimple m_data;
|
||||
bool insertNew(const string& sk, HistoryEntry &n, HistoryEntry &s);
|
||||
template<typename Tp> list<Tp> getHistory(const string& sk);
|
||||
};
|
||||
|
||||
template<typename Tp> list<Tp> RclHistory::getHistory(const string &sk)
|
||||
{
|
||||
list<Tp> mlist;
|
||||
Tp entry;
|
||||
list<string> names = m_data.getNames(sk);
|
||||
for (list<string>::const_iterator it = names.begin();
|
||||
it != names.end(); it++) {
|
||||
string value;
|
||||
if (m_data.get(*it, value, sk)) {
|
||||
if (!entry.decode(value))
|
||||
continue;
|
||||
mlist.push_front(entry);
|
||||
}
|
||||
}
|
||||
return mlist;
|
||||
}
|
||||
|
||||
#endif /* _HISTORY_H_INCLUDED_ */
|
||||
Reference in New Issue
Block a user