• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

Nepomuk-Core

  • sources
  • kde-4.12
  • kdelibs
  • nepomuk-core
  • libnepomukcore
  • query
queryparser.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the Nepomuk KDE project.
3  Copyright (C) 2007-2011 Sebastian Trueg <trueg@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19 
20 #include "queryparser.h"
21 #include "query.h"
22 #include "query_p.h"
23 #include "literalterm.h"
24 #include "resourceterm.h"
25 #include "andterm.h"
26 #include "orterm.h"
27 #include "negationterm.h"
28 #include "comparisonterm.h"
29 #include "dateparser_p.h"
30 #include "nfo.h"
31 #include "nie.h"
32 
33 #include <QtCore/QRegExp>
34 #include <QtCore/QSet>
35 #include <QtCore/QMutex>
36 #include <QtCore/QMutexLocker>
37 
38 #include <kdebug.h>
39 #include <klocale.h>
40 
41 #include "resourcemanager.h"
42 #include "property.h"
43 #include "literal.h"
44 
45 #include <Soprano/Node>
46 #include <Soprano/Model>
47 #include <Soprano/QueryResultIterator>
48 #include <Soprano/Vocabulary/RDFS>
49 #include <Soprano/Vocabulary/RDF>
50 #include <Soprano/Vocabulary/NAO>
51 
52 using namespace Soprano::Vocabulary;
53 using namespace Nepomuk2::Vocabulary;
54 
55 using namespace Nepomuk2::Query;
56 
57 namespace {
58  Nepomuk2::Query::ComparisonTerm::Comparator fieldTypeRelationFromString( const QString& s ) {
59  if ( s == "=" ) {
60  return Nepomuk2::Query::ComparisonTerm::Equal;
61  }
62  else if ( s == ":" ) {
63  return Nepomuk2::Query::ComparisonTerm::Contains;
64  }
65  else if ( s == ">" ) {
66  return Nepomuk2::Query::ComparisonTerm::Greater;
67  }
68  else if ( s == "<" ) {
69  return Nepomuk2::Query::ComparisonTerm::Smaller;
70  }
71  else if ( s == ">=" ) {
72  return Nepomuk2::Query::ComparisonTerm::GreaterOrEqual;
73  }
74  else if ( s == "<=" ) {
75  return Nepomuk2::Query::ComparisonTerm::SmallerOrEqual;
76  }
77  else {
78  kDebug() << "FIXME: Unsupported relation:" << s;
79  return Nepomuk2::Query::ComparisonTerm::Equal;
80  }
81  }
82 
83  QString stripQuotes( const QString& s, bool* hadQuotes = 0 ) {
84  if ( s[0] == '\'' ||
85  s[0] == '\"' ) {
86  if( hadQuotes )
87  *hadQuotes = true;
88  return s.mid( 1 ).left( s.length()-2 );
89  }
90  else {
91  if( hadQuotes )
92  *hadQuotes = false;
93  return s;
94  }
95  }
96 
97  QUrl tryToBeIntelligentAboutParsingUrl( const QString& s ) {
98  if ( s.contains( '%' ) && !s.contains( '/' ) ) {
99  return QUrl::fromEncoded( s.toAscii() );
100  }
101  else {
102  return QUrl( s );
103  }
104  }
105 
106  Soprano::LiteralValue createLiteral( const QString& s, bool globbing ) {
107  // 1. check if it is a number
108  QString clearString(s);
109  clearString.remove(QLatin1Char('\''));
110  clearString.remove(QLatin1Char('"'));
111  bool b = false;
112  int i = clearString.toInt( &b );
113  if ( b )
114  return Soprano::LiteralValue( i );
115  double d = clearString.toDouble( &b );
116  if ( b )
117  return Soprano::LiteralValue( d );
118 
119  // 2. no number - continue with the original string
120 
121  // no globbing if we have quotes or if there already is a wildcard
122  if ( s[0] == QLatin1Char('\'') ||
123  s[0] == QLatin1Char('\"') ) {
124  return s;
125  }
126 
127  //
128  // we can only do query term globbing for strings longer than 3 chars
129  //
130  if( globbing && s.length() > 3 && !s.endsWith('*') && !s.endsWith('?') )
131  return QString(s + '*');
132  else
133  return s;
134  }
135 
136  bool positiveTerm( const QString& s_ ) {
137  const QString s = s_.toLower().simplified();
138  if(s.isEmpty())
139  return true;
140  else if(s == "+")
141  return true;
142  else if(s == "-")
143  return false;
144  else if(s == "!")
145  return false;
146  else if(s == "not")
147  return false;
148  else //unrecognized capture
149  return true;
150  }
151 
152  // A filename pattern needs to contain one dot and at least one '*' or '?':
153  // *.mp3
154  // hello?.txt
155  // hello?.*
156  // test*.???
157  bool isFilenamePattern( const QString& s )
158  {
159  return( !s.contains(' ') &&
160  s.count('.') == 1 &&
161  s.count('*') + s.count('?') > 0 );
162  }
163 
164  Nepomuk2::Query::ComparisonTerm createFilenamePatternTerm( const QString& s )
165  {
166  QString regex = QRegExp::escape(s);
167  regex.replace( "\\*", QLatin1String( ".*" ) );
168  regex.replace( "\\?", QLatin1String( "." ) );
169  regex.replace("\\", "\\\\");
170  regex.prepend('^');
171  regex.append('$');
172  return Nepomuk2::Query::ComparisonTerm( Nepomuk2::Vocabulary::NFO::fileName(),
173  Nepomuk2::Query::LiteralTerm( regex ),
174  Nepomuk2::Query::ComparisonTerm::Regexp );
175  }
176 
186  Nepomuk2::Query::Term mergeLiteralTerms( const Nepomuk2::Query::Term& term )
187  {
188  if( term.isAndTerm() ) {
189  AndTerm mergedTerm;
190  QStringList fullTextTerms;
191  Q_FOREACH( const Term& st, term.toAndTerm().subTerms() ) {
192  if( st.isLiteralTerm() ) {
193  fullTextTerms << st.toLiteralTerm().value().toString();
194  }
195  else {
196  mergedTerm.addSubTerm( st );
197  }
198  }
199  mergedTerm.addSubTerm( LiteralTerm( fullTextTerms.join( QString::fromLatin1(" AND ") ) ) );
200  return mergedTerm.optimized();
201  }
202  else {
203  return term;
204  }
205  }
206 
213  bool setupComparisonTermSubTerm(Nepomuk2::Query::ComparisonTerm& ct)
214  {
215  // property with resource range
216  if(ct.property().range().isValid()) {
217  if(ct.subTerm().isLiteralTerm()) {
218  // here we need a string. everything else does not work since we match labels
219  return ct.subTerm().toLiteralTerm().value().isString();
220  }
221  else {
222  return true;
223  }
224  }
225 
226  // property with literal range
227  else if(ct.subTerm().isLiteralTerm()) {
228  // only strings can be matched via bif:contains
229  if(ct.comparator() == Nepomuk2::Query::ComparisonTerm::Contains &&
230  ct.property().literalRangeType().dataType() != QVariant::String) {
231  ct.setComparator(Nepomuk2::Query::ComparisonTerm::Equal);
232  }
233 
234  // try to convert the value via QVariant
235  QVariant v = ct.subTerm().toLiteralTerm().value().variant();
236  if(v.convert(ct.property().literalRangeType().dataType())) {
237  ct.setSubTerm(Nepomuk2::Query::LiteralTerm(v));
238  return true;
239  }
240 
241  // try some heuristics
242  else {
243  if(ct.property().literalRangeType().dataType() == QVariant::DateTime) {
244  // if it is an int with 4 digits it is very likely a year
245  if(ct.subTerm().toLiteralTerm().value().isInt() ) {
246  const int year = ct.subTerm().toLiteralTerm().value().toInt();
247  if( year >= 1000 && year <= 9999) {
248  QDate date(year, 1, 1);
249  QTime time(0,0);
250  // greater than last day in same year
251  // greater or equal than the first day in same year
252  // smaller than first day in same year
253  // smaller or equal than last day in same year
254  if(ct.comparator() == ComparisonTerm::Greater ||
255  ct.comparator() == ComparisonTerm::SmallerOrEqual) {
256  date.setYMD(date.year(), 12, 31);
257  time.setHMS(23,59,59,999);
258  }
259  ct.setSubTerm(Nepomuk2::Query::LiteralTerm(QDateTime(date, time)));
260  return true;
261  }
262  }
263  }
264  }
265  }
266 
267  // fallback
268  return false;
269  }
270 
271 #ifndef Q_CC_MSVC
272 #warning Make the parser handle different data, time, and datetime encodings as well as suffixes like MB or GB
273 #endif
274 #if 0
275  QDateTime parseDateTime( const Soprano::LiteralValue& literal )
276  {
277  //TODO: change to DateTime parser once complete
278  Nepomuk2::Search::DateParser date( literal.toString() );
279  if( date.hasDate() ) {
280  return QDateTime( date.getDate() );
281  }
282  else {
283  Nepomuk2::Search::TimeParser time( literal.toString() );
284  if(time.hasTime() )
285  return QDateTime(QDate::currentDate(), time.next() );
286  else
287  return QDateTime(); //return invalid datetime
288  }
289  }
290 
291 
292  Soprano::LiteralValue parseSizeType( const Soprano::LiteralValue& literal )
293  {
294  const double KiB = 1024.0;
295  const double MiB = KiB * 1024.0;
296  const double GiB = MiB * 1024.0;
297  const double TiB = GiB * 1024.0;
298 
299  const double KB = 1000.0;
300  const double MB = KB * 1000.0;
301  const double GB = MB * 1000.0;
302  const double TB = GB * 1000.0;
303 
304  QHash<QString, double> sizes;
305  sizes.insert( "KiB", KiB );
306  sizes.insert( "MiB", MiB );
307  sizes.insert( "GiB", GiB );
308  sizes.insert( "TiB", TiB );
309  sizes.insert( "KB", KB );
310  sizes.insert( "MB", MB );
311  sizes.insert( "GB", GB );
312  sizes.insert ("TB", TB );
313 
314  for ( QHash<QString, double>::const_iterator i = sizes.constBegin();
315  i != sizes.constEnd(); ++i ) {
316  QRegExp cur( QString("^([\\d]+.?[\\d]*)[\\s]*%1$").arg( i.key() ) );
317  if( cur.indexIn( literal.toString() ) != -1 ) {
318  double value = cur.cap( 1 ).toDouble();
319  double newValue = value * i.value();
320  kDebug() << "Found value" << value << i.key() << "->" << newValue;
321  return Soprano::LiteralValue( newValue );
322  }
323  }
324  return literal;
325  }
326 
327 
328  Nepomuk2::Query::Term resolveLiteralValues( const Nepomuk2::Query::Term& term )
329  {
330  switch( term.type() ) {
331  case Nepomuk2::Query::Term::Comparison: {
332  Nepomuk2::Query::ComparisonTerm cterm = term.toComparisonTerm();
333  Nepomuk2::Types::Property p( cterm.property() );
334  if ( p.literalRangeType().isValid() ) {
335  Q_ASSERT( cterm.subTerm().isLiteralTerm() );
336 
337  Nepomuk2::Query::ComparisonTerm newTerm;
338  newTerm.setComparator( cterm.comparator() );
339  newTerm.setProperty( QUrl(cterm.property()) );
340 
341  // now try to resolve the literal
342  const Nepomuk2::Query::LiteralTerm subTerm = cterm.subTerm().toLiteralTerm();
343  const Nepomuk2::Types::Literal lt = p.literalRangeType();
344  if ( lt.dataType() == QVariant::DateTime &&
345  !subTerm.value().isDateTime() ) {
346  QDateTime dateTime = parseDateTime( subTerm.value() );
347  if ( dateTime.isValid() ) {
348  newTerm.setSubTerm( Nepomuk2::Query::LiteralTerm( dateTime ) );
349  return newTerm;
350  }
351  }
352  else if ( lt.dataType() == QVariant::Int &&
353  !subTerm.value().isInt() ) {
354  newTerm.setSubTerm( Nepomuk2::Query::LiteralTerm( parseSizeType( subTerm.value() ) ) );
355  return newTerm;
356  }
357  }
358 
359  return term;
360  }
361 
362  case Nepomuk2::Query::Term::And:
363  case Nepomuk2::Query::Term::Or: {
364  QList<Nepomuk2::Query::Term> newSubTerms;
365  foreach( const Nepomuk2::Query::Term& t, static_cast<const Nepomuk2::Query::GroupTerm&>( term ).subTerms() ) {
366  newSubTerms << resolveLiteralValues(t);
367  }
368  if ( term.isAndTerm() )
369  return Nepomuk2::Query::AndTerm( newSubTerms );
370  else
371  return Nepomuk2::Query::OrTerm( newSubTerms );
372  }
373 
374  default:
375  return term;
376  }
377  }
378 #endif
379 
380  // a field differs from a plain term in that it does never allow comparators
381  const char* s_fieldNamePattern = "([^\\s\"':=<>]+|(?:([\"'])[^\"':=<>]+\\%1))";
382  const char* s_plainTermPattern = "([^-][^\\s\"':=<>]*|(?:([\"'])[^\"']+\\%1))";
383  const char* s_inExclusionPattern = "((?:[\\+\\-\\!]\\s*|[nN][oO][tT]\\s+)?)";
384  const char* s_uriPattern = "<([^<>]+)>";
385  const char* s_comparatorPattern = "(:|\\<=|\\>=|=|\\<|\\>)";
386 
391  class QueryParserRegExpPool
392  {
393  public:
394  QueryParserRegExpPool()
395  : plainTermRx( QLatin1String(s_inExclusionPattern)
396  + QString::fromLatin1(s_plainTermPattern).arg( 3 ) ),
397  fieldRx( QLatin1String(s_inExclusionPattern)
398  + QString::fromLatin1(s_fieldNamePattern).arg( 3 )
399  + QLatin1String(s_comparatorPattern)
400  + QString::fromLatin1(s_plainTermPattern).arg( 6 ) ),
401  propertyRx( QLatin1String(s_inExclusionPattern)
402  + QLatin1String(s_uriPattern)
403  + QLatin1String(s_comparatorPattern)
404  + QString::fromLatin1(s_plainTermPattern).arg( 5 ) ),
405  resourceRx( QLatin1String(s_inExclusionPattern)
406  + QLatin1String(s_uriPattern)
407  + QLatin1String("(?::|=)")
408  + QLatin1String(s_uriPattern) ),
409  fieldFieldRx( QLatin1String(s_inExclusionPattern)
410  + QString::fromLatin1(s_fieldNamePattern).arg( 3 )
411  + QLatin1String(s_comparatorPattern)
412  + QLatin1String("\\(")
413  + QString::fromLatin1(s_fieldNamePattern).arg( 6 )
414  + QLatin1String(s_comparatorPattern)
415  + QString::fromLatin1(s_plainTermPattern).arg( 9 )
416  + QLatin1String("\\)") )
417  {
418  }
419 
420  // match a simple search text
421  // captures: 1 - The optional + or - sign (may be empty)
422  // 2 - the search text (including optional paranthesis)
423  QRegExp plainTermRx;
424 
425  // match a field search term: fieldname + relation (:, =, etc) + search text with optional paranthesis
426  // captures: 1 - The optional + or - sign (may be empty)
427  // 2 - fieldname
428  // 3 - relation
429  // 4 - search text (including optional paranthesis)
430  QRegExp fieldRx;
431 
432  // match a property URI search term: property URI + relation (:, =, etc) + search text with optional paranthesis
433  // captures: 1 - The optional + or - sign (may be empty)
434  // 2 - property URI
435  // 3 - relation
436  // 4 - search text (including optional paranthesis)
437  QRegExp propertyRx;
438 
439  // match a property URI search term: property URI + relation (:, =, etc) + resource URI
440  // captures: 1 - The optional + or - sign (may be empty)
441  // 2 - property URI
442  // 3 - resource URI
443  QRegExp resourceRx;
444 
445  QRegExp fieldFieldRx;
446  };
447 
448  // the one global instance used for the statis QueryParser methods
449  K_GLOBAL_STATIC( QueryParserRegExpPool, s_regExpPool )
450 }
451 
452 
453 class Nepomuk2::Query::QueryParser::Private
454 {
455 public:
456  QueryParser* q;
457 
458  QSet<QString> andKeywords;
459  QSet<QString> orKeywords;
460  mutable QHash<QString, QList<Types::Property> > fieldMatchCache;
461  QMutex fieldMatchCacheMutex;
462 
464  bool m_invalidQuery;
465 
472  Nepomuk2::Query::Term resolveFields( const Nepomuk2::Query::Term& term );
473 };
474 
475 
476 
477 Term QueryParser::Private::resolveFields(const Term &term)
478 {
479  switch( term.type() ) {
480  case Nepomuk2::Query::Term::And:
481  case Nepomuk2::Query::Term::Or: {
482  QList<Nepomuk2::Query::Term> newSubTerms;
483  foreach( const Nepomuk2::Query::Term& t, static_cast<const Nepomuk2::Query::GroupTerm&>( term ).subTerms() ) {
484  Nepomuk2::Query::Term resolvedTerm = resolveFields(t);
485  if ( resolvedTerm.isValid() )
486  newSubTerms << resolvedTerm;
487  else
488  return Nepomuk2::Query::Term();
489  }
490  if ( term.isAndTerm() )
491  return Nepomuk2::Query::AndTerm( newSubTerms );
492  else
493  return Nepomuk2::Query::OrTerm( newSubTerms );
494  }
495 
496 
497  case Nepomuk2::Query::Term::Negation: {
498  return Nepomuk2::Query::NegationTerm::negateTerm( resolveFields( term.toNegationTerm().subTerm() ) );
499  }
500 
501 
502  case Nepomuk2::Query::Term::Comparison: {
503  Nepomuk2::Query::ComparisonTerm newTerm;
504  newTerm.setComparator( term.toComparisonTerm().comparator() );
505  newTerm.setProperty( term.toComparisonTerm().property() );
506  newTerm.setSubTerm( resolveFields( term.toComparisonTerm().subTerm() ) );
507 
508  // A very dumb test to see if the property is set or not: does the URI have a scheme.
509  // With a proper parser and in-place property matching there will be no need for this anymore
510  if ( newTerm.property().uri().scheme().isEmpty() ) {
511  QList<Nepomuk2::Types::Property> properties = q->matchProperty( term.toComparisonTerm().property().uri().toString() );
512  // we only use a max of 4 properties, otherwise the queries get too big
513  // in addition we try to exclude properties which do not make sense:
514  // - numerical values can never match a resource
515  Nepomuk2::Query::OrTerm orTerm;
516  for( int i = 0; i < properties.count() && orTerm.subTerms().count() < 4; ++i ) {
517  const Nepomuk2::Types::Property& property = properties[i];
518  Nepomuk2::Query::ComparisonTerm t( newTerm );
519  t.setProperty( property );
520  if(setupComparisonTermSubTerm(t)) {
521  orTerm.addSubTerm( t );
522  }
523  }
524  if(!orTerm.isValid()) {
525  m_invalidQuery = true;
526  return Nepomuk2::Query::Term();
527  }
528  return orTerm.optimized();
529  }
530  }
531 
532  default:
533  return term;
534  }
535 }
536 
537 
538 Nepomuk2::Query::QueryParser::QueryParser()
539  : d( new Private() )
540 {
541  d->q = this;
542 
543  QString andListStr = i18nc( "Boolean AND keyword in desktop search strings. "
544  "You can add several variants separated by spaces, "
545  "e.g. retain the English one alongside the translation; "
546  "keywords are not case sensitive. Make sure there is "
547  "no conflict with the OR keyword.",
548  "and" );
549  foreach ( const QString &andKeyword, andListStr.split( ' ', QString::SkipEmptyParts ) ) {
550  d->andKeywords.insert( andKeyword.toLower() );
551  }
552  QString orListStr = i18nc( "Boolean OR keyword in desktop search strings. "
553  "You can add several variants separated by spaces, "
554  "e.g. retain the English one alongside the translation; "
555  "keywords are not case sensitive. Make sure there is "
556  "no conflict with the AND keyword.",
557  "or" );
558  foreach ( const QString &orKeyword, orListStr.split( ' ', QString::SkipEmptyParts ) ) {
559  d->orKeywords.insert( orKeyword.toLower() );
560  }
561 
562  // These are going to be the most frequently matched
563  // We are including them so as to speed up the queries as otherwise each of these keywords
564  // maps to multiple properties
565  d->fieldMatchCache.insert( QLatin1String("hastag"), QList<Types::Property>() << Types::Property(NAO::hasTag()) );
566  d->fieldMatchCache.insert( QLatin1String("rating"), QList<Types::Property>() << Types::Property(NAO::numericRating()) );
567  d->fieldMatchCache.insert( QLatin1String("comment"), QList<Types::Property>() << Types::Property(NAO::description()) );
568  d->fieldMatchCache.insert( QLatin1String("mimetype"), QList<Types::Property>() << Types::Property(NIE::mimeType()) );
569 }
570 
571 
572 Nepomuk2::Query::QueryParser::~QueryParser()
573 {
574  delete d;
575 }
576 
577 
578 QList<Nepomuk2::Types::Property> Nepomuk2::Query::QueryParser::matchProperty( const QString& fieldName ) const
579 {
580  kDebug() << fieldName;
581 
582  QMutexLocker lock( &d->fieldMatchCacheMutex );
583 
584  QHash<QString, QList<Types::Property> >::ConstIterator it = d->fieldMatchCache.constFind( fieldName );
585  if( it != d->fieldMatchCache.constEnd() ) {
586  return it.value();
587  }
588  else {
589  lock.unlock();
590 
591  QList<Nepomuk2::Types::Property> results;
592 
593  //
594  // Due to the limited number of properties in the database a REGEX filter
595  // is actually faster than a fulltext query via bif:contains (this is what
596  // experiments showed).
597  //
598  QString query = QString( "select distinct ?p where { "
599  "graph ?g { "
600  "?p a %1 . "
601  "?p %2 ?l . "
602  "FILTER(REGEX(STR(?l),'%3*','i') || REGEX(STR(?p),'%3*','i')) . "
603  "} "
604  "}" )
605  .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::RDF::Property() ) )
606  .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::RDFS::label() ) )
607  .arg( fieldName );
608  kDebug() << "Match query:" << query;
609 
610  Soprano::QueryResultIterator labelHits
611  = Nepomuk2::ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql );
612 
613  while ( labelHits.next() ) {
614  QUrl property = labelHits.binding( "p" ).uri();
615  results << property;
616  kDebug() << "Found property match" << property;
617  }
618 
619  lock.relock();
620  d->fieldMatchCache.insert( fieldName, results );
621  return results;
622  }
623 }
624 
625 
626 Nepomuk2::Query::Query Nepomuk2::Query::QueryParser::parse( const QString& query ) const
627 {
628  return parse( query, NoParserFlags );
629 }
630 
631 
632 Nepomuk2::Query::Query Nepomuk2::Query::QueryParser::parse( const QString& query, ParserFlags flags ) const
633 {
634  // TODO: a "real" parser which can handle all of the Xesam user language
635  // This one for example does not handle nesting at all.
636 
637  Nepomuk2::Query::Query final;
638  QList<Term> terms;
639 
640  bool inOrBlock = false;
641  bool inAndBlock = false;
642 
643  int pos = 0;
644 
645  // create local copies of the regexps for thread safety purposes
646  const QRegExp resourceRx = s_regExpPool->resourceRx;
647  const QRegExp propertyRx = s_regExpPool->propertyRx;
648  const QRegExp fieldFieldRx = s_regExpPool->fieldFieldRx;
649  const QRegExp fieldRx = s_regExpPool->fieldRx;
650  const QRegExp plainTermRx = s_regExpPool->plainTermRx;
651 
652  while ( pos < query.length() ) {
653  // skip whitespace
654  while ( pos < query.length() && query[pos].isSpace() ) {
655  kDebug() << "Skipping space at" << pos;
656  ++pos;
657  }
658 
659  Term term;
660 
661  if ( pos < query.length() ) {
662  if ( resourceRx.indexIn( query, pos ) == pos ) {
663  kDebug() << "matched resource term at" << pos << resourceRx.cap( 0 );
664  term = ComparisonTerm( tryToBeIntelligentAboutParsingUrl( resourceRx.cap( 2 ) ),
665  ResourceTerm( tryToBeIntelligentAboutParsingUrl( resourceRx.cap( 3 ) ) ),
666  ComparisonTerm::Equal );
667  if ( !positiveTerm( resourceRx.cap( 1 ) ) ) {
668  term = NegationTerm::negateTerm( term );
669  }
670  pos += resourceRx.matchedLength();
671  }
672 
673  else if ( propertyRx.indexIn( query, pos ) == pos ) {
674  kDebug() << "matched property term at" << pos << propertyRx.cap( 0 );
675  ComparisonTerm ct;
676  ct.setProperty( tryToBeIntelligentAboutParsingUrl( propertyRx.cap( 2 ) ) );
677  ct.setSubTerm( LiteralTerm( createLiteral( propertyRx.cap( 4 ), flags&QueryTermGlobbing ) ) );
678  QString comparator = propertyRx.cap( 3 );
679  ct.setComparator( fieldTypeRelationFromString( comparator ) );
680  pos += propertyRx.matchedLength();
681 
682  if ( !positiveTerm(propertyRx.cap( 1 ) ) ) {
683  term = NegationTerm::negateTerm( ct );
684  }
685  else {
686  term = ct;
687  }
688  }
689 
690  else if ( fieldFieldRx.indexIn( query, pos ) == pos ) {
691  kDebug() << "matched field field term at" << pos
692  << fieldFieldRx.cap( 0 )
693  << fieldFieldRx.cap( 2 )
694  << fieldFieldRx.cap( 4 )
695  << fieldFieldRx.cap( 5 )
696  << fieldFieldRx.cap( 7 )
697  << fieldFieldRx.cap( 8 );
698  ComparisonTerm ct;
699  ct.setProperty( QUrl(stripQuotes( fieldFieldRx.cap( 2 ) )) );
700  QString comparator = fieldFieldRx.cap( 4 );
701  ct.setComparator( fieldTypeRelationFromString( comparator ) );
702  ct.setSubTerm( ComparisonTerm( QUrl(stripQuotes( fieldFieldRx.cap( 5 ) )),
703  LiteralTerm( createLiteral( fieldFieldRx.cap( 8 ), flags&QueryTermGlobbing ) ),
704  fieldTypeRelationFromString( fieldFieldRx.cap( 7 ) ) ) );
705  pos += fieldFieldRx.matchedLength();
706 
707  if ( !positiveTerm( fieldFieldRx.cap( 1 ) ) ) {
708  term = NegationTerm::negateTerm( ct );
709  }
710  else {
711  term = ct;
712  }
713  }
714 
715  else if ( fieldRx.indexIn( query, pos ) == pos ) {
716  kDebug() << "matched field term at" << pos << fieldRx.cap( 0 ) << fieldRx.cap( 2 ) << fieldRx.cap( 4 ) << fieldRx.cap( 5 );
717  if( stripQuotes ( fieldRx.cap( 2 ) ).compare( QString( "inFolder" ), Qt::CaseInsensitive ) == 0 ) {
718  KUrl url( fieldRx.cap( 5 ) );
719  kDebug() << "found include path" << url;
720  FileQuery fileQuery(final);
721  if ( positiveTerm( fieldRx.cap( 1 ) ) )
722  fileQuery.addIncludeFolder(url);
723  else
724  fileQuery.addExcludeFolder(url);
725  final = fileQuery;
726  pos += fieldRx.matchedLength();
727  }
728  else {
729  ComparisonTerm ct;
730  ct.setProperty( QUrl( stripQuotes( fieldRx.cap( 2 ) ) ) );
731  ct.setSubTerm( LiteralTerm( createLiteral( fieldRx.cap( 5 ), flags&QueryTermGlobbing ) ) );
732  QString comparator = fieldRx.cap( 4 );
733  ct.setComparator( fieldTypeRelationFromString( comparator ) );
734  pos += fieldRx.matchedLength();
735  if ( !positiveTerm(fieldRx.cap( 1 ) ) ) {
736  NegationTerm nt;
737  nt.setSubTerm( ct );
738  term = nt;
739  }
740  else {
741  term = ct;
742  }
743  }
744  }
745 
746  else if ( plainTermRx.indexIn( query, pos ) == pos ) {
747  QString value = plainTermRx.cap( 2 );
748  if ( d->orKeywords.contains( value.toLower() ) ) {
749  inOrBlock = true;
750  }
751  else if ( d->andKeywords.contains( value.toLower() ) ) {
752  inAndBlock = true;
753  }
754  else {
755  kDebug() << "matched literal at" << pos << value;
756  if( flags&DetectFilenamePattern && isFilenamePattern(value) ) {
757  term = createFilenamePatternTerm( value );
758  }
759  else {
760  term = LiteralTerm( createLiteral( value, flags&QueryTermGlobbing ) );
761  }
762  if ( !positiveTerm(plainTermRx.cap( 1 ) ) ) {
763  term = NegationTerm::negateTerm( term );
764  }
765  }
766  pos += plainTermRx.matchedLength();
767  }
768 
769  else {
770  kDebug() << "Invalid query at" << pos << query;
771  return Query();
772  }
773 
774  if ( term.isValid() ) {
775  if ( inOrBlock && !terms.isEmpty() ) {
776  OrTerm orTerm;
777  orTerm.addSubTerm( terms.takeLast() );
778  orTerm.addSubTerm( term );
779  terms.append( orTerm );
780  }
781  else if ( inAndBlock && !terms.isEmpty() ) {
782  AndTerm andTerm;
783  andTerm.addSubTerm( terms.takeLast() );
784  andTerm.addSubTerm( term );
785  terms.append( andTerm );
786  }
787  else {
788  terms.append( term );
789  }
790  }
791  }
792  }
793 
794  if ( terms.count() == 1 ) {
795  final.setTerm( terms[0] );
796  }
797  else if ( terms.count() > 0 ) {
798  AndTerm t;
799  t.setSubTerms( terms );
800  final.setTerm( t );
801  }
802 
803  d->m_invalidQuery = false;
804  final.setTerm( mergeLiteralTerms( d->resolveFields( final.term() ) ) );
805  if(d->m_invalidQuery) {
806  return Query();
807  }
808  else {
809  return final;
810  }
811 }
812 
813 
814 // static
815 Nepomuk2::Query::Query Nepomuk2::Query::QueryParser::parseQuery( const QString& query )
816 {
817  QueryParser parser;
818  return parser.parse( query );
819 }
820 
821 
822 // static
823 Nepomuk2::Query::Query Nepomuk2::Query::QueryParser::parseQuery( const QString& query, ParserFlags flags )
824 {
825  QueryParser parser;
826  return parser.parse( query, flags );
827 }
Nepomuk2::Types::Property::range
Class range()
The range of the property.
Definition: libnepomukcore/types/property.cpp:233
andterm.h
Nepomuk2::Query::ComparisonTerm::setComparator
void setComparator(Comparator)
Set the comparator.
Definition: comparisonterm.cpp:474
Nepomuk2::Query::ComparisonTerm::Smaller
A LiteralTerm sub-term is matched to smaller literal values.
Definition: comparisonterm.h:104
Nepomuk2::Query::Term::Comparison
A comparison.
Definition: term.h:113
Nepomuk2::Query::QueryParser::QueryParser
QueryParser()
Create a new query parser.
Definition: queryparser.cpp:538
Nepomuk2::Query::Term::toLiteralTerm
LiteralTerm toLiteralTerm() const
Interpret this term as a LiteralTerm.
Definition: term.cpp:211
Nepomuk2::Query::ComparisonTerm::setProperty
void setProperty(const Types::Property &)
Set the property for ComparisonTerm Terms.
Definition: comparisonterm.cpp:481
Nepomuk2::Query::AndTerm
Match resource that match all sub terms.
Definition: andterm.h:43
Nepomuk2::Query::FileQuery::addExcludeFolder
void addExcludeFolder(const KUrl &folder)
Add a folder to exclude from the search.
Definition: filequery.cpp:96
resourceterm.h
Nepomuk2::Query::Term::Negation
A negation term inverts the meaning of its sub term.
Definition: term.h:127
Nepomuk2::Types::Entity::uri
QUrl uri() const
The URI of the resource.
Definition: entity.cpp:175
Nepomuk2::Query::ComparisonTerm::Greater
A LiteralTerm sub-term is matched to greater literal values.
Definition: comparisonterm.h:99
Nepomuk2::Query::Term
The base class for all term types.
Definition: term.h:64
Nepomuk2::Query::SimpleTerm::setSubTerm
void setSubTerm(const Term &term)
Set the sub term to match against.
Definition: simpleterm.cpp:59
Nepomuk2::Query::ComparisonTerm::GreaterOrEqual
A LiteralTerm sub-term is matched to greater or equal literal values.
Definition: comparisonterm.h:109
Nepomuk2::Query::Term::isAndTerm
bool isAndTerm() const
Definition: term.cpp:187
Nepomuk2::Query::NegationTerm::negateTerm
static Term negateTerm(const Term &term)
Negate term.
Definition: negationterm.cpp:101
QHash
Nepomuk2::Query::SimpleTerm::subTerm
Term subTerm() const
The sub term to match against.
Definition: simpleterm.cpp:52
negationterm.h
Nepomuk2::Query::GroupTerm::subTerms
QList< Term > subTerms() const
The sub terms that are combined in this group.
Definition: groupterm.cpp:94
Nepomuk2::Query::Term::optimized
Term optimized() const
Optimizes the term without changing its meaning.
Definition: term.cpp:99
Nepomuk2::Query::Term::And
Match all resources that match all sub terms.
Definition: term.h:98
Nepomuk2::Query::ComparisonTerm::Equal
A sub-term is matched one-to-one.
Definition: comparisonterm.h:94
query.h
Nepomuk2::Types::Property::literalRangeType
Literal literalRangeType()
If the rage of this property is a literal (i.e.
Definition: libnepomukcore/types/property.cpp:271
Nepomuk2::Query::ComparisonTerm::Regexp
A LiteralTerm sub-term is matched against a string literal value using the literal term's value as a ...
Definition: comparisonterm.h:89
Nepomuk2::Query::NegationTerm
Negate an arbitrary term.
Definition: negationterm.h:47
Nepomuk2::Query::Term::toComparisonTerm
ComparisonTerm toComparisonTerm() const
Interpret this term as a ComparisonTerm.
Definition: term.cpp:266
Nepomuk2::Query::GroupTerm::setSubTerms
void setSubTerms(const QList< Term > &terms)
Set the sub terms that are combined in this group.
Definition: groupterm.cpp:101
Nepomuk2::Types::Literal::dataType
QVariant::Type dataType() const
The type converted to a QVariant::Type.
Definition: literal.cpp:118
Nepomuk2::Query::ComparisonTerm::SmallerOrEqual
A LiteralTerm sub-term is matched to smaller or equal literal values.
Definition: comparisonterm.h:114
Nepomuk2::Query::FileQuery
A Nepomuk desktop query specialized for file searches.
Definition: filequery.h:44
Nepomuk2::Query::ComparisonTerm
A term matching the value of a property.
Definition: comparisonterm.h:70
Nepomuk2::Query::Query
A Nepomuk desktop query.
Definition: query.h:76
Nepomuk2::Query::Term::isLiteralTerm
bool isLiteralTerm() const
Definition: term.cpp:163
Nepomuk2::Query::OrTerm
Match resource that match at least one of the sub terms.
Definition: orterm.h:43
Nepomuk2::Query::ComparisonTerm::Comparator
Comparator
ComparisonTerm supports different ways to compare values.
Definition: comparisonterm.h:76
Nepomuk2::Types::Property
A property is a resource of type rdf:Property which relates a domain with a range.
Definition: libnepomukcore/types/property.h:52
Nepomuk2::Types::Literal
Defines a literal type based on XML Schema.
Definition: literal.h:41
Nepomuk2::ResourceManager::instance
static ResourceManager * instance()
Definition: resourcemanager.cpp:270
resourcemanager.h
Nepomuk2::Query::QueryParser::parse
Query parse(const QString &query) const
Parse a user query.
Definition: queryparser.cpp:626
Nepomuk2::Query::QueryParser::~QueryParser
~QueryParser()
Destructor.
Definition: queryparser.cpp:572
Nepomuk2::Query::QueryParser::matchProperty
QList< Types::Property > matchProperty(const QString &fieldName) const
Try to match a field name as used in a query string to actual properties.
Definition: queryparser.cpp:578
Nepomuk2::Query::QueryParser::parseQuery
static Query parseQuery(const QString &query)
Convenience method to quickly parse a query without creating an object.
Definition: queryparser.cpp:815
Nepomuk2::Query::ComparisonTerm::comparator
Comparator comparator() const
The Comparator used by ComparisonTerm Terms.
Definition: comparisonterm.cpp:460
comparisonterm.h
literalterm.h
Nepomuk2::Query::QueryParser
Parser for desktop user queries.
Definition: queryparser.h:90
Nepomuk2::Query::GroupTerm::addSubTerm
void addSubTerm(const Term &term)
Add a sub term to the list of terms that are combined in this group.
Definition: groupterm.cpp:108
Nepomuk2::Query::Term::toAndTerm
AndTerm toAndTerm() const
Interpret this term as a AndTerm.
Definition: term.cpp:248
Nepomuk2::Query::FileQuery::addIncludeFolder
void addIncludeFolder(const KUrl &folder)
Add a folder to include in the search.
Definition: filequery.cpp:57
Nepomuk2::Query::ComparisonTerm::Contains
A LiteralTerm sub-term is matched against string literal values.
Definition: comparisonterm.h:81
orterm.h
literal.h
Nepomuk2::Types::Entity::isValid
bool isValid() const
Is this a valid Entity, i.e.
Definition: entity.cpp:259
Nepomuk2::ResourceManager::mainModel
Soprano::Model * mainModel()
Retrieve the main data storage model.
Definition: resourcemanager.cpp:363
Nepomuk2::Query::Term::type
Type type() const
Definition: term.cpp:84
Nepomuk2::Query::Term::isValid
bool isValid() const
Definition: term.cpp:78
Nepomuk2::Query::Term::Or
Match all resources that match one of the sub terms.
Definition: term.h:105
Nepomuk2::Query::ComparisonTerm::property
Types::Property property() const
A property used for ComparisonTerm Terms.
Definition: comparisonterm.cpp:467
Nepomuk2::Query::LiteralTerm
Match literal properties via full text.
Definition: literalterm.h:86
queryparser.h
Nepomuk2::Query::ResourceTerm
Matches exactly one resource.
Definition: resourceterm.h:52
Nepomuk2::Query::LiteralTerm::value
Soprano::LiteralValue value() const
The value this LiteralTerm should match to.
Definition: literalterm.cpp:262
Nepomuk2::Query::Term::toNegationTerm
NegationTerm toNegationTerm() const
Interpret this term as a NegationTerm.
Definition: term.cpp:230
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:08 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Nepomuk-Core

Skip menu "Nepomuk-Core"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal