5 #include <QtCore/QFileInfo>
6 #include <QtCore/QTextStream>
7 #include <QtCore/QList>
10 #include <kfilemetainfo.h>
11 #include <kapplication.h>
12 #include <kmessagebox.h>
14 #include <kstandarddirs.h>
17 KQuery::KQuery(QObject
*parent
)
19 m_sizemode(0), m_sizeboundary1(0), m_sizeboundary2(0),
20 m_timeFrom(0), m_timeTo(0),
21 job(0), m_insideCheckEntries(false), m_result(0)
23 processLocate
= new KProcess(this);
24 connect(processLocate
,SIGNAL(readyReadStandardOutput()),this,SLOT(slotreadyReadStandardOutput()));
25 connect(processLocate
,SIGNAL(readyReadStandardError()),this,SLOT(slotreadyReadStandardError()));
26 connect(processLocate
,SIGNAL(finished(int, QProcess::ExitStatus
)),this,SLOT(slotendProcessLocate(int, QProcess::ExitStatus
)));
28 // Files with these mime types can be ignored, even if
29 // findFormatByFileContent() in some cases may claim that
30 // these are text files:
31 ignore_mimetypes
.append("application/pdf");
32 ignore_mimetypes
.append("application/postscript");
34 // PLEASE update the documentation when you add another
36 ooo_mimetypes
.append("application/vnd.sun.xml.writer");
37 ooo_mimetypes
.append("application/vnd.sun.xml.calc");
38 ooo_mimetypes
.append("application/vnd.sun.xml.impress");
39 // OASIS mimetypes, used by OOo-2.x and KOffice >= 1.4
40 //ooo_mimetypes.append("application/vnd.oasis.opendocument.chart");
41 //ooo_mimetypes.append("application/vnd.oasis.opendocument.graphics");
42 //ooo_mimetypes.append("application/vnd.oasis.opendocument.graphics-template");
43 //ooo_mimetypes.append("application/vnd.oasis.opendocument.formula");
44 //ooo_mimetypes.append("application/vnd.oasis.opendocument.image");
45 ooo_mimetypes
.append("application/vnd.oasis.opendocument.presentation-template");
46 ooo_mimetypes
.append("application/vnd.oasis.opendocument.presentation");
47 ooo_mimetypes
.append("application/vnd.oasis.opendocument.spreadsheet-template");
48 ooo_mimetypes
.append("application/vnd.oasis.opendocument.spreadsheet");
49 ooo_mimetypes
.append("application/vnd.oasis.opendocument.text-template");
50 ooo_mimetypes
.append("application/vnd.oasis.opendocument.text");
51 // KOffice-1.3 mimetypes
52 koffice_mimetypes
.append("application/x-kword");
53 koffice_mimetypes
.append("application/x-kspread");
54 koffice_mimetypes
.append("application/x-kpresenter");
59 while (!m_regexps
.isEmpty())
60 delete m_regexps
.takeFirst();
61 while (!m_fileItems
.isEmpty())
62 m_fileItems
.dequeue();
68 job
->kill(KJob::EmitResult
);
69 if (processLocate
->state() == QProcess::Running
)
70 processLocate
->kill();
71 while (!m_fileItems
.isEmpty())
72 m_fileItems
.dequeue();
77 while (!m_fileItems
.isEmpty())
78 m_fileItems
.dequeue();
79 if(m_useLocate
) //use "locate" instead of the internal search method
82 processLocate
->clearProgram();
83 *processLocate
<< "locate";
84 *processLocate
<< m_url
.path( KUrl::AddTrailingSlash
).toLatin1();
86 processLocate
->setNextOpenMode(QIODevice::Text
);
87 processLocate
->setOutputChannelMode(KProcess::SeparateChannels
);
88 processLocate
->start();
93 job
= KIO::listRecursive( m_url
, KIO::HideProgressInfo
);
95 job
= KIO::listDir( m_url
, KIO::HideProgressInfo
);
97 connect(job
, SIGNAL(entries(KIO::Job
*, const KIO::UDSEntryList
&)),
98 SLOT(slotListEntries(KIO::Job
*, const KIO::UDSEntryList
&)));
99 connect(job
, SIGNAL(result(KJob
*)), SLOT(slotResult(KJob
*)));
100 connect(job
, SIGNAL(canceled(KJob
*)), SLOT(slotCanceled(KJob
*)));
103 void KQuery::slotResult( KJob
* _job
)
105 if (job
!= _job
) return;
108 m_result
=_job
->error();
112 void KQuery::slotCanceled( KJob
* _job
)
114 if (job
!= _job
) return;
117 while (!m_fileItems
.isEmpty())
118 m_fileItems
.dequeue();
120 m_result
=KIO::ERR_USER_CANCELED
;
124 void KQuery::slotListEntries(KIO::Job
*, const KIO::UDSEntryList
& list
)
126 const KIO::UDSEntryList::ConstIterator end
= list
.constEnd();
127 for (KIO::UDSEntryList::ConstIterator it
= list
.constBegin(); it
!= end
; ++it
)
129 m_fileItems
.enqueue(KFileItem(*it
, m_url
, true, true));
134 void KQuery::checkEntries()
136 if (m_insideCheckEntries
)
138 m_insideCheckEntries
=true;
139 metaKeyRx
=new QRegExp(m_metainfokey
);
140 metaKeyRx
->setPatternSyntax( QRegExp::Wildcard
);
141 while ( !m_fileItems
.isEmpty() )
143 processQuery( m_fileItems
.dequeue() );
147 m_insideCheckEntries
=false;
149 emit
result(m_result
);
152 /* List of files found using slocate */
153 void KQuery::slotListEntries( QStringList list
)
155 metaKeyRx
=new QRegExp(m_metainfokey
);
156 metaKeyRx
->setPatternSyntax( QRegExp::Wildcard
);
158 QStringList::const_iterator it
= list
.constBegin();
159 QStringList::const_iterator end
= list
.constEnd();
161 for (; it
!= end
; ++it
)
163 processQuery( KFileItem( KFileItem::Unknown
, KFileItem::Unknown
, KUrl(*it
)) );
169 /* Check if file meets the find's requirements*/
170 void KQuery::processQuery( const KFileItem
&file
)
173 if ( file
.name() == "." || file
.name() == ".." )
178 QListIterator
<QRegExp
*> nextItem( m_regexps
);
179 while ( nextItem
.hasNext() )
181 QRegExp
*reg
= nextItem
.next();
182 matched
= matched
|| ( reg
== 0L ) || ( reg
->exactMatch( file
.url().fileName( KUrl::IgnoreTrailingSlash
) ) ) ;
188 // make sure the files are in the correct range
191 case 1: // "at least"
192 if ( file
.size() < m_sizeboundary1
) return;
195 if ( file
.size() > m_sizeboundary1
) return;
198 if ( file
.size() != m_sizeboundary1
) return;
201 if ( (file
.size() < m_sizeboundary1
) ||
202 (file
.size() > m_sizeboundary2
) ) return;
204 case 0: // "none" -> Fall to default
209 // make sure it's in the correct date range
210 // what about 0 times?
211 if ( m_timeFrom
&& m_timeFrom
> file
.time(KFileItem::ModificationTime
).toTime_t() )
213 if ( m_timeTo
&& m_timeTo
< file
.time(KFileItem::ModificationTime
).toTime_t() )
216 // username / group match
217 if ( (!m_username
.isEmpty()) && (m_username
!= file
.user()) )
219 if ( (!m_groupname
.isEmpty()) && (m_groupname
!= file
.group()) )
227 case 1: // plain file
228 if ( !S_ISREG( file
.mode() ) )
236 if ( !file
.isLink() )
240 if ( !S_ISCHR ( file
.mode() ) && !S_ISBLK ( file
.mode() ) &&
241 !S_ISFIFO( file
.mode() ) && !S_ISSOCK( file
.mode() ) )
245 if ( (file
.permissions() & 0111) != 0111 || file
.isDir() )
249 if ( (file
.permissions() & 04000) != 04000 ) // fixme
253 if (!m_mimetype
.isEmpty() && !m_mimetype
.contains(file
.mimetype()))
257 // match data in metainfo...
258 if ((!m_metainfo
.isEmpty()) && (!m_metainfokey
.isEmpty()))
260 bool foundmeta
=false;
261 QString filename
= file
.url().path();
263 if(filename
.startsWith("/dev/"))
266 KFileMetaInfo
metadatas(filename
);
267 QStringList metakeys
;
268 QString strmetakeycontent
;
270 metakeys
= metadatas
.supportedKeys();
271 for (QStringList::const_iterator it
= metakeys
.constBegin(); it
!= metakeys
.constEnd(); ++it
)
273 if (!metaKeyRx
->exactMatch(*it
))
275 strmetakeycontent
=metadatas
.item(*it
).value().toString();
276 if(strmetakeycontent
.indexOf(m_metainfo
)!=-1)
287 QString matchingLine
;
288 if (!m_context
.isEmpty())
291 if( !m_search_binary
&& ignore_mimetypes
.indexOf(file
.mimetype()) != -1 ) {
292 kDebug() << "ignoring, mime type is in exclusion list: " << file
.url();
297 bool isZippedOfficeDocument
=false;
298 int matchingLineNumber
=0;
300 // FIXME: doesn't work with non local files
303 QTextStream
* stream
=0;
306 QByteArray zippedXmlFileContent
;
308 // KWord's and OpenOffice.org's files are zipped...
309 if( ooo_mimetypes
.indexOf(file
.mimetype()) != -1 ||
310 koffice_mimetypes
.indexOf(file
.mimetype()) != -1 )
312 KZip
zipfile(file
.url().path());
313 KZipFileEntry
*zipfileEntry
;
315 if(zipfile
.open(QIODevice::ReadOnly
))
317 const KArchiveDirectory
*zipfileContent
= zipfile
.directory();
319 if( koffice_mimetypes
.indexOf(file
.mimetype()) != -1 )
320 zipfileEntry
= (KZipFileEntry
*)zipfileContent
->entry("maindoc.xml");
322 zipfileEntry
= (KZipFileEntry
*)zipfileContent
->entry("content.xml"); //for OpenOffice.org
325 kWarning() << "Expected XML file not found in ZIP archive " << file
.url() ;
329 zippedXmlFileContent
= zipfileEntry
->data();
330 xmlTags
.setPattern("<.*>");
331 xmlTags
.setMinimal(true);
332 stream
= new QTextStream(zippedXmlFileContent
, QIODevice::ReadOnly
);
333 stream
->setCodec("UTF-8");
334 isZippedOfficeDocument
= true;
336 kWarning() << "Cannot open supposed ZIP file " << file
.url() ;
338 } else if( !m_search_binary
&& !file
.mimetype().startsWith("text/") &&
339 file
.url().isLocalFile() ) {
340 if ( KMimeType::isBinaryData(file
.url().path()) ) {
341 kDebug() << "ignoring, not a text file: " << file
.url();
346 if(!isZippedOfficeDocument
) //any other file or non-compressed KWord
348 filename
= file
.url().path();
349 if(filename
.startsWith("/dev/"))
351 qf
.setFileName(filename
);
352 qf
.open(QIODevice::ReadOnly
);
353 stream
=new QTextStream(&qf
);
354 stream
->setCodec(QTextCodec::codecForLocale());
357 while ( ! stream
->atEnd() )
359 QString str
= stream
->readLine();
360 matchingLineNumber
++;
362 if (str
.isNull()) break;
363 if(isZippedOfficeDocument
)
364 str
.replace(xmlTags
, "");
366 if (m_regexpForContent
)
368 if (m_regexp
.indexIn(str
)>=0)
370 matchingLine
=QString::number(matchingLineNumber
)+": "+str
;
377 if (str
.indexOf(m_context
, 0, m_casesensitive
?Qt::CaseSensitive
:Qt::CaseInsensitive
) != -1)
379 matchingLine
=QString::number(matchingLineNumber
)+": "+str
;
384 kapp
->processEvents();
391 emit
addFile(file
,matchingLine
);
394 void KQuery::setContext(const QString
& context
, bool casesensitive
,
395 bool search_binary
, bool useRegexp
)
398 m_casesensitive
= casesensitive
;
399 m_search_binary
= search_binary
;
400 m_regexpForContent
=useRegexp
;
401 if ( !m_regexpForContent
)
402 m_regexp
.setPatternSyntax(QRegExp::Wildcard
);
404 m_regexp
.setPatternSyntax(QRegExp::RegExp
);
406 m_regexp
.setCaseSensitivity(Qt::CaseSensitive
);
408 m_regexp
.setCaseSensitivity(Qt::CaseInsensitive
);
409 if (m_regexpForContent
)
410 m_regexp
.setPattern(m_context
);
413 void KQuery::setMetaInfo(const QString
&metainfo
, const QString
&metainfokey
)
416 m_metainfokey
=metainfokey
;
419 void KQuery::setMimeType(const QStringList
&mimetype
)
421 m_mimetype
= mimetype
;
424 void KQuery::setFileType(int filetype
)
426 m_filetype
= filetype
;
429 void KQuery::setSizeRange(int mode
, KIO::filesize_t value1
, KIO::filesize_t value2
)
432 m_sizeboundary1
= value1
;
433 m_sizeboundary2
= value2
;
436 void KQuery::setTimeRange(time_t from
, time_t to
)
442 void KQuery::setUsername(const QString
&username
)
444 m_username
= username
;
447 void KQuery::setGroupname(const QString
&groupname
)
449 m_groupname
= groupname
;
452 void KQuery::setRegExp(const QString
®exp
, bool caseSensitive
)
456 const QStringList strList
=regexp
.split( sep
, QString::SkipEmptyParts
);
457 // QRegExp globChars ("[\\*\\?\\[\\]]", TRUE, FALSE);
458 while (!m_regexps
.isEmpty())
459 delete m_regexps
.takeFirst();
461 // m_regexpsContainsGlobs.clear();
462 for ( QStringList::ConstIterator it
= strList
.constBegin(); it
!= strList
.constEnd(); ++it
) {
463 regExp
= new QRegExp((*it
),( caseSensitive
? Qt::CaseSensitive
: Qt::CaseInsensitive
), QRegExp::Wildcard
);
464 // m_regexpsContainsGlobs.append(regExp->pattern().contains(globChars));
465 m_regexps
.append(regExp
);
469 void KQuery::setRecursive(bool recursive
)
471 m_recursive
= recursive
;
474 void KQuery::setPath(const KUrl
&url
)
479 void KQuery::setUseFileIndex(bool useLocate
)
481 m_useLocate
=useLocate
;
484 void KQuery::slotreadyReadStandardError()
486 KMessageBox::error(NULL
, QString::fromLocal8Bit(processLocate
->readAllStandardOutput()), i18n("Error while using locate"));
489 void KQuery::slotreadyReadStandardOutput()
491 bufferLocate
+= processLocate
->readAllStandardOutput();
494 void KQuery::slotendProcessLocate(int, QProcess::ExitStatus
)
496 if(bufferLocate
.isEmpty())
502 QString str
= QString::fromLocal8Bit(bufferLocate
);
503 bufferLocate
.clear();
504 slotListEntries(str
.split('\n'));
508 #include "kquery.moc"