plasma-framework/runnercontext.cpp
Aaron J. Seigo 6019dc7b27 huge patch, but it's needed to avoid crashes and i can't wait on other people's pending work forever. so...
QueryMatch by value! shared dptr == no copy of data either! so (nearly) all the speed love of pointers with none of the crash hate. woo!

RunnerContext also by value! die pointers die!

also get rid of tons of locking that just doesn't make sense anymore; get rid of data priority enum as well since it's completely meaningless.

speed, glory, stability! ftw!

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=805661
2008-05-09 03:49:11 +00:00

231 lines
5.9 KiB
C++

/*
* Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "runnercontext.h"
#include <QReadWriteLock>
#include <QFile>
#include <QFileInfo>
#include <QSharedData>
#include <KCompletion>
#include <KDebug>
#include <KMimeType>
#include <KShell>
#include <KStandardDirs>
#include <KUrl>
#include "querymatch.h"
//#define LOCK_FOR_READ(context) if (context->d->policy == Shared) { context->d->lock.lockForRead(); }
//#define LOCK_FOR_WRITE(context) if (context->d->policy == Shared) { context->d->lock.lockForWrite(); }
//#define UNLOCK(context) if (context->d->policy == Shared) { context->d->lock.unlock(); }
#define LOCK_FOR_READ(context) context->d->lock.lockForRead();
#define LOCK_FOR_WRITE(context) context->d->lock.lockForWrite();
#define UNLOCK(context) context->d->lock.unlock();
namespace Plasma
{
class RunnerContext::Private : public QSharedData
{
public:
Private(RunnerContext *context)
: QSharedData(),
type(RunnerContext::UnknownType),
q(context)
{
}
Private(const RunnerContext::Private& p)
: QSharedData(),
type(RunnerContext::None),
q(p.q)
{
//kDebug() << "¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿boo yeah" << type;
}
~Private()
{
}
/**
* Determines type of query
*/
void determineType()
{
// NOTE! this method must NEVER be called from
// code that may be running in multiple threads
// with the same data.
type = UnknownType;
QString path = KShell::tildeExpand(term);
int space = term.indexOf(' ');
if (space > 0) {
if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
type = ShellCommand;
}
} else if (!KStandardDirs::findExe(path.left(space)).isEmpty()) {
type = Executable;
} else {
KUrl url(term);
if (!url.protocol().isEmpty() && !url.host().isEmpty()) {
type = NetworkLocation;
} else if (QFile::exists(path)) {
QFileInfo info(path);
if (info.isDir()) {
type = Directory;
mimeType = "inode/folder";
} else {
type = File;
KMimeType::Ptr mimeTypePtr = KMimeType::findByPath(path);
if (mimeTypePtr) {
mimeType = mimeTypePtr->name();
}
}
}
}
}
QReadWriteLock lock;
QList<QueryMatch> matches;
QString term;
QString mimeType;
RunnerContext::Type type;
RunnerContext * q;
};
RunnerContext::RunnerContext(QObject *parent)
: QObject(parent),
d(new Private(this))
{
}
//copy ctor
RunnerContext::RunnerContext(RunnerContext &other, QObject *parent)
: QObject(parent)
{
LOCK_FOR_READ((&other))
d = other.d;
UNLOCK((&other))
}
RunnerContext::~RunnerContext()
{
}
void RunnerContext::reset()
{
// We will detach if we are a copy of someone. But we will reset
// if we are the 'main' context others copied from. Resetting
// one RunnerContext makes all the copies oneobsolete.
d.detach();
// we still have to remove all the matches, since if the
// ref count was 1 (e.g. only the RunnerContext is using
// the dptr) then we won't get a copy made
if (!d->matches.isEmpty()) {
d->matches.clear();
emit d->q->matchesChanged();
}
d->term.clear();
d->mimeType.clear();
d->type = UnknownType;
//kDebug() << "match count" << d->matches.count();
}
void RunnerContext::setQuery(const QString &term)
{
reset();
if (term.isEmpty()) {
return;
}
d->term = term;
d->determineType();
}
QString RunnerContext::query() const
{
// the query term should never be set after
// a search starts. in fact, reset() ensures this
// and setQuery(QString) calls reset()
return d->term;
}
RunnerContext::Type RunnerContext::type() const
{
return d->type;
}
QString RunnerContext::mimeType() const
{
return d->mimeType;
}
bool RunnerContext::addMatches(const QString& term, const QList<QueryMatch> &matches)
{
Q_UNUSED(term)
if (matches.isEmpty()) {
return false;
}
LOCK_FOR_WRITE(this)
d->matches << matches;
UNLOCK(this);
//kDebug()<< "add matches";
// A copied searchContext may share the d pointer,
// we always want to sent the signal of the object that created
// the d pointer
emit d->q->matchesChanged();
return true;
}
bool RunnerContext::addMatch(const QString &term, const QueryMatch &match)
{
Q_UNUSED(term)
LOCK_FOR_WRITE(this)
d->matches << match;
UNLOCK(this);
//kDebug()<< "added match" << match->text();
emit d->q->matchesChanged();
return true;
}
QList<QueryMatch> RunnerContext::matches() const
{
LOCK_FOR_READ(this)
QList<QueryMatch> matches = d->matches;
UNLOCK(this);
return matches;
}
}
#include "runnercontext.moc"