You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeaddons/noatun-plugins/oblique/base.cpp

436 lines
7.9 KiB

// Copyright (c) 2003 Charles Samuels <charles@kde.org>
// See the file COPYING for redistribution terms.
#include "base.h"
#include "file.h"
#include "kdbt.h"
#include "kbuffer.h"
#include <tqstringlist.h>
#include <tqmap.h>
#include <tqfile.h>
#include <tqdom.h>
#include <cstdlib>
#include <assert.h>
#include <db_cxx.h>
struct Base::Private
{
Private() : db(0, DB_CXX_NO_EXCEPTIONS) { }
Db db;
typedef KDbt<FileId> Key;
typedef KDbt<TQStringList> Data;
FileId high;
FileId cachedId;
mutable TQMap<TQString,TQString> cachedProperties;
TQPtrList<Slice> slices;
int sliceHigh;
};
Base::Base(const TQString &file)
{
d = new Private;
d->cachedId = 0;
TQCString filename = TQFile::encodeName(file);
bool create = true;
if (d->db.open(
#if DB_VERSION_MINOR > 0 && DB_VERSION_MAJOR >= 4
NULL,
#endif
filename,
0, DB_BTREE, DB_NOMMAP, 0
)==0)
{ // success
Private::Data data;
Private::Key key(0);
if (d->db.get(0, &key, &data, 0)==0)
{
TQStringList strs;
data.get(strs);
mFormatVersion = strs[0].toUInt(0, 16); // TODO
d->high = strs[1].toUInt();
if (strs.count() == 3)
loadMetaXML(strs[2]);
else
loadMetaXML("");
create=false;
}
}
if (create)
{ // failure
TQFile(filename).remove();
d->db.open(
#if DB_VERSION_MINOR > 0 && DB_VERSION_MAJOR >= 4
NULL,
#endif
filename,0, DB_BTREE, DB_NOMMAP|DB_CREATE,0
);
d->high=0;
TQStringList strs;
strs << "00010002" << "0" << "";
resetFormatVersion();
loadMetaXML("");
Private::Data data(strs);
Private::Key key(0);
// in the stringlist for Key(0), we have the following list:
// { "version of the file",
// "the high extreme (auto-increment counter in SQL terminology)",
// "the metaxml"
// }
d->db.put(0, &key, &data, 0);
}
}
void Base::resetFormatVersion()
{
mFormatVersion = 0x00010002;
}
Base::~Base()
{
TQStringList strs;
strs << TQString::number(mFormatVersion, 16) << TQString::number(d->high);
strs << saveMetaXML();
Private::Data data(strs);
Private::Key key(0);
d->db.put(0, &key, &data, 0);
d->db.sync(0);
d->db.close(0);
delete d;
}
File Base::add(const TQString &file)
{
Private::Key key(++d->high);
TQStringList properties;
properties << "file" << file;
Private::Data data(properties);
unless (d->db.put(0, &key, &data, 0))
{
// success !
File f(this, d->high);
f.makeCache();
emit added(f);
return f;
}
return File();
}
File Base::find(FileId id)
{
if (id == 0) return File();
Private::Key key(id);
Private::Data data;
unless (d->db.get(0, &key, &data, 0))
{
// exists
return File(this, id);
}
else
{
return File(); // null item
}
}
void Base::clear()
{
for (FileId id = high(); id >= 1; id--)
{
File f = find(id);
if (f)
f.remove();
}
}
FileId Base::high() const
{
return d->high;
}
File Base::first(FileId first)
{
if (first > high()) return File();
while (!find(first))
{
++first;
if (first > high())
return File();
}
return File(this, first);
}
TQString Base::property(FileId id, const TQString &property) const
{
loadIntoCache(id);
if (!d->cachedProperties.contains(property)) return TQString();
TQMap<TQString,TQString>::Iterator i = d->cachedProperties.find(property);
return i.data();
}
void Base::setProperty(FileId id, const TQString &key, const TQString &value)
{
loadIntoCache(id);
d->cachedProperties.insert(key, value);
// reinsert it into the DB
TQStringList props;
for (
TQMap<TQString,TQString>::Iterator i(d->cachedProperties.begin());
i != d->cachedProperties.end(); ++i
)
{
props << i.key() << i.data();
}
Private::Data data(props);
Private::Key dbkey(id);
d->db.put(0, &dbkey, &data, 0);
d->db.sync(0);
emit modified(File(this, id));
}
TQStringList Base::properties(FileId id) const
{
loadIntoCache(id);
TQStringList props;
for (
TQMap<TQString,TQString>::Iterator i(d->cachedProperties.begin());
i != d->cachedProperties.end(); ++i
)
{
props << i.key();
}
return props;
}
void Base::clearProperty(FileId id, const TQString &key)
{
loadIntoCache(id);
d->cachedProperties.remove(key);
// reinsert it into the DB
TQStringList props;
for (
TQMap<TQString,TQString>::Iterator i(d->cachedProperties.begin());
i != d->cachedProperties.end(); ++i
)
{
if (i.key() != key)
props << i.key() << i.data();
}
Private::Data data(props);
Private::Key dbkey(id);
d->db.put(0, &dbkey, &data, 0);
d->db.sync(0);
emit modified(File(this, id));
}
void Base::remove(File file)
{
Private::Key key(file.id());
unless (d->db.del(0, &key, 0))
{
emit removed(file);
if (file.id() == d->high)
{
d->high--; // optimization
}
}
d->db.sync(0);
}
void Base::loadIntoCache(FileId id) const
{
if (d->cachedId == id) return;
d->cachedId = id;
d->cachedProperties.clear();
Private::Key key(id);
Private::Data data;
unless (d->db.get(0, &key, &data, 0))
{
TQStringList props;
data.get(props);
if (props.count() % 2)
{ // corrupt?
const_cast<Base*>(this)->remove(File(const_cast<Base*>(this), id));
return;
}
for (TQStringList::Iterator i(props.begin()); i != props.end(); ++i)
{
TQString &key = *i;
TQString &value = *++i;
d->cachedProperties.insert(key, value);
}
}
}
TQString Base::saveMetaXML()
{
TQDomDocument doc;
doc.setContent(TQString("<meta />"));
TQDomElement doce = doc.documentElement();
TQDomElement e = doc.createElement("slices");
e.setAttribute("highslice", TQString::number(d->sliceHigh));
doce.appendChild(e);
for (TQPtrListIterator<Slice> i(d->slices); *i; ++i)
{
TQDomElement slice = doc.createElement("slice");
slice.setAttribute("id", (*i)->id());
slice.setAttribute("name", (*i)->name());
e.appendChild(slice);
}
return doc.toString();
}
void Base::move(FileId oldid, FileId newid)
{
Private::Key key(oldid);
Private::Data data;
unless (d->db.get(0, &key, &data, 0))
{
TQStringList props;
data.get(props);
d->db.del(0, &key, 0);
Private::Key key2(newid);
d->db.put(0, &key2, &data, 0);
}
}
void Base::dump()
{
for (FileId id=1; id <= high(); id++)
{
TQStringList props = properties(id);
std::cerr << id << '.';
for (TQStringList::Iterator i(props.begin()); i != props.end(); ++i)
{
TQString prop = *i;
std::cerr << ' ' << prop.latin1() << '=' << property(id, prop).latin1();
}
std::cerr << std::endl;
}
}
void Base::notifyChanged(const File &file)
{
emit modified(file);
}
TQPtrList<Slice> Base::slices()
{
return d->slices;
}
Slice *Base::addSlice(const TQString &name)
{
Slice *sl = new Slice(this, d->sliceHigh++, name);
d->slices.append(sl);
slicesModified();
return sl;
}
Slice *Base::defaultSlice()
{
for (TQPtrListIterator<Slice> i(d->slices); *i; ++i)
{
if ((*i)->id() == 0) return *i;
}
abort();
return 0;
}
void Base::removeSlice(Slice *slice)
{
assert(slice->id() > 0);
d->slices.removeRef(slice);
delete slice;
}
Slice *Base::sliceById(int id)
{
for (TQPtrListIterator<Slice> i(d->slices); *i; ++i)
{
if ((*i)->id() == id) return *i;
}
return 0;
}
void Base::loadMetaXML(const TQString &xml)
{
d->slices.setAutoDelete(true);
d->slices.clear();
d->slices.setAutoDelete(false);
TQDomDocument doc;
doc.setContent(xml);
TQDomElement doce = doc.documentElement();
bool loadedId0=false;
for (TQDomNode n = doce.firstChild(); !n.isNull(); n = n.nextSibling())
{
TQDomElement e = n.toElement();
if (e.isNull()) continue;
if (e.tagName().lower() == "slices")
{
d->sliceHigh = e.attribute("highslice", "1").toInt();
for (TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
{
TQDomElement e = n.toElement();
if (e.isNull()) continue;
if (e.tagName().lower() == "slice")
{
int id = e.attribute("id").toInt();
if (id==0 && loadedId0) break;
loadedId0=true;
TQString name = e.attribute("name");
d->slices.append(new Slice(this, id, name));
}
}
}
}
if (d->slices.count() == 0)
{
// we must have a default
d->slices.append(new Slice(this, 0, ""));
}
}
#include "base.moc"