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/query.cpp

571 lines
11 KiB

// Copyright (c) 2003 Charles Samuels <charles@kde.org>
// See the file COPYING for redistribution terms.
#include "query.h"
#include "file.h"
#include <iostream>
#include <tdelocale.h>
#include <tqdom.h>
#include <tqfile.h>
QueryGroup::QueryGroup()
{
mFirstChild=0;
mNextSibling=0;
mFuzzyness = Case | Spaces | Articles;
mOptions = AutoHide;
}
QueryGroup::QueryGroup(const QueryGroup &copy)
{
mFirstChild=0;
mNextSibling=0;
operator=(copy);
}
QueryGroup &QueryGroup::operator =(const QueryGroup &copy)
{
mFuzzyness = copy.mFuzzyness;
mOptions = copy.mOptions;
mPropertyName = copy.mPropertyName;
mPresentation = copy.mPresentation;
mValue = copy.mValue;
return *this;
}
QueryGroup::~QueryGroup()
{
delete mFirstChild;
delete mNextSibling;
}
void QueryGroup::insertAfter(QueryGroup *insert)
{
QueryGroup *oldAfter = mNextSibling;
insert->setNextSibling(oldAfter);
setNextSibling(insert);
}
void QueryGroup::insertUnder(QueryGroup *insert)
{
QueryGroup *oldUnder = mFirstChild;
insert->setNextSibling(oldUnder);
setFirstChild(insert);
}
void QueryGroup::move(Query *query, QueryGroup *under, QueryGroup *after)
{
query->dump();
query->take(this);
if (after) after->insertAfter(this);
else if (under) under->insertUnder(this);
else query->insertFirst(this);
query->dump();
}
QueryGroup *QueryGroup::previous(Query *query)
{
QueryGroup *f = query->firstChild();
if (f == this) return 0;
return previous(f);
}
QueryGroup *QueryGroup::previous(QueryGroup *startWith)
{
QueryGroup *current = startWith;
QueryGroup *after = 0;
while (current)
{
after = current->nextSibling();
if (after == this)
return current;
if (QueryGroup *child = current->firstChild())
{
if (child == this)
return current;
child = previous(child);
if (child) return child;
}
current = after;
}
return 0;
}
QueryGroup *QueryGroup::lastChild()
{
QueryGroup *first = mFirstChild;
if (!first) return 0;
while (first->nextSibling())
first = first->nextSibling();
return first;
}
bool QueryGroup::fuzzyness(Fuzzyness f) const
{
return mFuzzyness & f;
}
bool QueryGroup::option(Option option) const
{
return mOptions & option;
}
void QueryGroup::setOption(Option option, bool on)
{
if (on)
mOptions |= option;
else
mOptions &= ~option;
}
bool QueryGroup::matches(const File &file) const
{
TQString prop = file.property(propertyName());
prop = prop.simplifyWhiteSpace();
if (prop.isNull()) prop = "";
TQRegExp re(value());
return re.search(prop) != -1;
}
TQString QueryGroup::presentation(const File &file) const
{
// "$(property)"
TQString format=presentation();
TQRegExp find("(?:(?:\\\\\\\\))*\\$\\((.*)");
int start=0;
while (start != -1)
{
start = find.search(format, start);
if (start == -1) break;
// test if there's an odd amount of backslashes
if (start>0 && format[start-1]=='\\')
{
// yes, so half the amount of backslashes
// count how many there are first
TQRegExp counter("([\\\\]+)");
counter.search(format, start-1);
uint len=counter.cap(1).length()-1;
// and half them, and remove one more
format.replace(start-1, len/2+1, "");
start=start-1+len/2+find.cap(1).length()+3;
continue;
}
// now replace the backslashes with half as many
if (format[start]=='\\')
{
// count how many there are first
TQRegExp counter("([\\\\]+)");
counter.search(format, start);
uint len=counter.cap(1).length();
// and half them
format.replace(start, len/2, "");
start=start+len/2;
}
// "sth"foo"sth"
TQString cont(find.cap(1));
TQString prefix,suffix,propname;
unsigned int i=0;
if (cont[i] == '"')
{
i++;
for (; i < cont.length(); i++)
{
if (cont[i] != '"')
prefix += cont[i];
else
break;
}
i++;
}
for (; i < cont.length(); ++i)
{
if (cont[i]!='"' && cont[i]!=')')
propname += cont[i];
else
break;
}
if (cont[i] == '"')
{
i++;
for (; i < cont.length(); i++)
{
if (cont[i] != '"')
suffix += cont[i];
else
break;
}
i++;
}
i++;
TQString propval = file.property(propname);
// the following code won't be enabled until the presentation is reloaded
// at the best times
/* if (propname == "length")
{
int len = propval.toInt();
if ( len < 0 ) // no file loaded
propval = "--:--";
int secs = length()/1000; // convert milliseconds -> seconds
int seconds = secs % 60;
propval.sprintf("%.2d:%.2d", ((secs-seconds)/60), seconds);
}
*/
if (propval.length())
{
propval = prefix+propval+suffix;
format.replace(start, i+2, propval);
start += propval.length();
}
else
{
format.replace(start, i+2, "");
}
}
return format;
}
Query::Query()
{
mGroupFirst=0;
}
Query::~Query()
{
delete mGroupFirst;
}
Query::Query(const Query &copy)
{
mGroupFirst = 0;
operator=(copy);
}
Query &Query::operator =(const Query &copy)
{
if (&copy == this) return *this;
delete mGroupFirst;
mGroupFirst=0;
if (const QueryGroup *parent = copy.firstChild())
{
mGroupFirst = new QueryGroup(*parent);
deepCopy(parent->firstChild(), mGroupFirst);
}
return *this;
}
QueryGroup *Query::firstChild()
{
return mGroupFirst;
}
const QueryGroup *Query::firstChild() const
{
return mGroupFirst;
}
void Query::setFirstChild(QueryGroup *g)
{
mGroupFirst = g;
}
void Query::insertFirst(QueryGroup *g)
{
g->setNextSibling(mGroupFirst);
mGroupFirst = g;
}
void Query::clear()
{
delete mGroupFirst;
mGroupFirst=0;
}
TQString Query::load(const TQString &filename)
{
TQFile file(filename);
unless (file.open(IO_ReadOnly)) return TQString();
TQDomDocument doc;
doc.setContent(&file);
return load(doc.documentElement());
}
TQString Query::load(TQDomElement element)
{
clear();
if (element.tagName().lower() == "obliqueschema")
{
TQDomNode node = element.firstChild();
while (!node.isNull())
{
TQDomElement e = node.toElement();
if (e.tagName().lower() == "group")
loadGroup(e);
node = node.nextSibling();
}
}
else
{
return TQString();
}
// for internationalization:
// Add these if you create new schemas and release them with Oblique
(void)I18N_NOOP("Standard");
TQString title = element.attribute("title");
if (element.hasAttribute("standard"))
title = i18n(title.utf8());
return title;
}
void Query::save(const TQString &name, TQDomElement &element)
{
element.setTagName("ObliqueSchema");
element.setAttribute("version", "1.0");
element.setAttribute("title", name);
for (QueryGroup *g = firstChild(); g; g = g->nextSibling())
saveGroup(element, g);
}
void Query::save(const TQString &name, const TQString &filename)
{
TQFile file(filename);
unless (file.open(IO_Truncate|IO_ReadWrite ))
return;
TQDomDocument doc("ObliqueSchema");
doc.setContent(TQString("<!DOCTYPE ObliqueSchema><ObliqueSchema/>"));
TQDomElement e = doc.documentElement();
save(name, e);
TQTextStream ts(&file);
ts.setEncoding(TQTextStream::UnicodeUTF8);
// scourge elimination
TQString data = doc.toString();
TQString old = data;
while (data.replace(TQRegExp("([\n\r]+)(\t*) "), "\\1\\2\t") != old)
{
old = data;
}
ts << data;
}
void Query::take(QueryGroup *item)
{
QueryGroup *previous = item->previous(this);
if (!previous)
{
mGroupFirst = item->nextSibling();
item->setNextSibling(0);
return;
}
if (previous->nextSibling() == item)
{
previous->setNextSibling(item->nextSibling());
item->setNextSibling(0);
}
else if (previous->firstChild() == item)
{
previous->setFirstChild(item->nextSibling());
item->setNextSibling(0);
}
}
static void dump(QueryGroup *item, int depth)
{
if (!item) return;
do
{
for (int d = 0; d < depth; d++)
std::cerr << " ";
std::cerr << "prop: " << item->propertyName().utf8().data() << " pres: "
<< item->presentation().utf8().data() << std::endl;
dump(item->firstChild(), depth+1);
} while ((item = item->nextSibling()));
}
void Query::dump()
{
::dump(firstChild(), 0);
}
void Query::loadGroup(TQDomElement element, QueryGroup *parent)
{
TQDomNode node = element.firstChild();
QueryGroup *group = new QueryGroup;
if (parent)
{
if (QueryGroup *last = parent->lastChild())
last->setNextSibling(group);
else
parent->setFirstChild(group);
}
else
{
mGroupFirst = group;
}
while (!node.isNull())
{
TQDomElement e = node.toElement();
if (e.tagName().lower() == "group")
{
loadGroup(e, group);
}
else if (e.tagName().lower() == "property")
{
group->setPropertyName(e.text());
}
else if (e.tagName().lower() == "value")
{
group->setValue(TQRegExp(e.text()));
}
else if (e.tagName().lower() == "presentation")
{
group->setPresentation(e.text());
}
else if (e.tagName().lower() == "options")
{
TQDomNode node = e.firstChild();
while (!node.isNull())
{
TQDomElement e = node.toElement();
if (e.tagName().lower() == "disabled")
group->setOption(QueryGroup::Disabled, true);
else if (e.tagName().lower() == "unique") // backwards compat (for now)
group->setOption(QueryGroup::Playable, true);
else if (e.tagName().lower() == "playable")
group->setOption(QueryGroup::Playable, true);
else if (e.tagName().lower() == "childrenvisible")
group->setOption(QueryGroup::ChildrenVisible, true);
else if (e.tagName().lower() == "autoopen")
group->setOption(QueryGroup::AutoOpen, true);
node = node.nextSibling();
}
}
node = node.nextSibling();
}
}
void Query::saveGroup(TQDomElement &parent, QueryGroup *group)
{
TQDomDocument doc = parent.ownerDocument();
TQDomElement element = doc.createElement("group");
parent.appendChild(element);
TQDomElement childe;
TQDomText childtext;
{
childe = doc.createElement("property");
element.appendChild(childe);
childtext = doc.createTextNode(group->propertyName());
childe.appendChild(childtext);
}
{
childe = doc.createElement("value");
element.appendChild(childe);
childtext = doc.createTextNode(group->value().pattern());
childe.appendChild(childtext);
}
{
childe = doc.createElement("presentation");
element.appendChild(childe);
childtext = doc.createTextNode(group->presentation());
childe.appendChild(childtext);
}
{
childe = doc.createElement("options");
element.appendChild(childe);
if (group->option(QueryGroup::Disabled))
childe.appendChild(doc.createElement("disabled"));
if (group->option(QueryGroup::Playable))
childe.appendChild(doc.createElement("playable"));
if (group->option(QueryGroup::ChildrenVisible))
childe.appendChild(doc.createElement("childrenvisible"));
if (group->option(QueryGroup::AutoOpen))
childe.appendChild(doc.createElement("autoopen"));
}
for (QueryGroup *c = group->firstChild(); c; c = c->nextSibling())
{
saveGroup(element, c);
}
}
void Query::deepCopy(const QueryGroup *from, QueryGroup *toParent)
{
if (!from) return;
QueryGroup *last=0;
while (from)
{
QueryGroup *copy = new QueryGroup(*from);
if (last)
{
last->setNextSibling(copy);
last = copy;
}
else
{
toParent->setFirstChild(copy);
last = copy;
}
deepCopy(from->firstChild(), last);
from = from->nextSibling();
}
}