Mercurial > hg > easyhg-kdiff3
comparison kdiff3/src/fileaccess.cpp @ 8:86d21651c8db
KDiff3 version 0.9.70
author | joachim99 |
---|---|
date | Mon, 06 Oct 2003 18:50:45 +0000 |
parents | |
children | 59cf49d1fb90 |
comparison
equal
deleted
inserted
replaced
7:ff98a43bbfea | 8:86d21651c8db |
---|---|
1 /*************************************************************************** | |
2 * Copyright (C) 2003 by Joachim Eibl * | |
3 * joachim.eibl@gmx.de * | |
4 * * | |
5 * This program is free software; you can redistribute it and/or modify * | |
6 * it under the terms of the GNU General Public License as published by * | |
7 * the Free Software Foundation; either version 2 of the License, or * | |
8 * (at your option) any later version. * | |
9 ***************************************************************************/ | |
10 | |
11 #include "fileaccess.h" | |
12 #include <iostream> | |
13 #include <kio/global.h> | |
14 #include <kmessagebox.h> | |
15 #include "optiondialog.h" | |
16 #include <qlayout.h> | |
17 #include <qlabel.h> | |
18 #include <qapplication.h> | |
19 #if QT_VERSION==230 | |
20 #else | |
21 #include <qeventloop.h> | |
22 #endif | |
23 #include "common.h" | |
24 #include <ktempfile.h> | |
25 #include <qdir.h> | |
26 #include <qregexp.h> | |
27 #include <qtextstream.h> | |
28 #include <vector> | |
29 #include <klocale.h> | |
30 | |
31 #include <sys/types.h> | |
32 #include <sys/stat.h> | |
33 | |
34 #ifdef _WIN32 | |
35 #include <sys/utime.h> | |
36 #include <io.h> | |
37 #else | |
38 #include <unistd.h> // Needed for creating symbolic links via symlink(). | |
39 #include <utime.h> | |
40 #endif | |
41 | |
42 | |
43 ProgressDialog* g_pProgressDialog; | |
44 | |
45 | |
46 FileAccess::FileAccess( const QString& name, bool bWantToWrite ) | |
47 { | |
48 setFile( name, bWantToWrite ); | |
49 } | |
50 | |
51 FileAccess::FileAccess() | |
52 { | |
53 m_bValidData = false; | |
54 m_size = 0; | |
55 m_creationTime = QDateTime(); | |
56 m_accessTime = QDateTime(); | |
57 m_modificationTime = QDateTime(); | |
58 m_bReadable = false; | |
59 m_bWritable = false; | |
60 m_bExecutable = false; | |
61 m_bLocal = false; | |
62 m_bHidden = false; | |
63 m_bExists = false; | |
64 m_bFile = false; | |
65 m_bDir = false; | |
66 m_bSymLink = false; | |
67 } | |
68 | |
69 FileAccess::~FileAccess() | |
70 { | |
71 if( !m_localCopy.isEmpty() ) | |
72 { | |
73 removeFile( m_localCopy ); | |
74 } | |
75 } | |
76 | |
77 void FileAccess::setFile( const QString& name, bool bWantToWrite ) | |
78 { | |
79 m_url = KURL::fromPathOrURL( name ); | |
80 m_bValidData = false; | |
81 | |
82 m_size = 0; | |
83 m_creationTime = QDateTime(); | |
84 m_accessTime = QDateTime(); | |
85 m_modificationTime = QDateTime(); | |
86 m_bReadable = false; | |
87 m_bWritable = false; | |
88 m_bExecutable = false; | |
89 m_bHidden = false; | |
90 m_bExists = false; | |
91 m_bFile = false; | |
92 m_bDir = false; | |
93 m_bSymLink = false; | |
94 m_linkTarget = ""; | |
95 m_fileType = -1; | |
96 | |
97 // Note: Checking if the filename-string is empty is necessary for Win95/98/ME. | |
98 // The isFile() / isDir() queries would cause the program to crash. | |
99 // (This is a Win95-bug which has been corrected only in WinNT/2000/XP.) | |
100 if ( !name.isEmpty() ) | |
101 { | |
102 if ( m_url.isLocalFile() || !m_url.isValid() ) // assuming that malformed means relative | |
103 { | |
104 QString localName = name; | |
105 if ( m_url.isLocalFile() && name.left(5).lower()=="file:" ) | |
106 { | |
107 localName = m_url.path(); // I want the path without preceding "file:" | |
108 } | |
109 QFileInfo fi( localName ); | |
110 m_bReadable = fi.isReadable(); | |
111 m_bWritable = fi.isWritable(); | |
112 m_bExecutable = fi.isExecutable(); | |
113 #if QT_VERSION==230 | |
114 m_creationTime = fi.lastModified(); | |
115 m_bHidden = false; | |
116 #else | |
117 m_creationTime = fi.created(); | |
118 m_bHidden = fi.isHidden(); | |
119 #endif | |
120 m_modificationTime = fi.lastModified(); | |
121 m_accessTime = fi.lastRead(); | |
122 m_size = fi.size(); | |
123 m_bSymLink = fi.isSymLink(); | |
124 m_bFile = fi.isFile(); | |
125 m_bDir = fi.isDir(); | |
126 m_bExists = fi.exists(); | |
127 m_name = fi.fileName(); | |
128 m_path = fi.filePath(); | |
129 m_absFilePath= fi.absFilePath(); | |
130 if ( m_bSymLink ) m_linkTarget = fi.readLink(); | |
131 m_bLocal = true; | |
132 m_bValidData = true; | |
133 if ( ! m_url.isValid() ) | |
134 { | |
135 m_url.setPath( m_absFilePath ); | |
136 } | |
137 } | |
138 else | |
139 { | |
140 m_absFilePath = name; | |
141 m_name = m_url.fileName(); | |
142 m_bLocal = false; | |
143 | |
144 FileAccessJobHandler jh( this ); // A friend, which writes to the parameters of this class! | |
145 jh.stat(2/*all details*/, bWantToWrite); // returns bSuccess, ignored | |
146 | |
147 m_path = name; | |
148 } | |
149 } | |
150 } | |
151 | |
152 void FileAccess::addPath( const QString& txt ) | |
153 { | |
154 m_url.addPath( txt ); | |
155 setFile( m_url.url() ); // reinitialise | |
156 } | |
157 | |
158 /* Filetype: | |
159 S_IFMT 0170000 bitmask for the file type bitfields | |
160 S_IFSOCK 0140000 socket | |
161 S_IFLNK 0120000 symbolic link | |
162 S_IFREG 0100000 regular file | |
163 S_IFBLK 0060000 block device | |
164 S_IFDIR 0040000 directory | |
165 S_IFCHR 0020000 character device | |
166 S_IFIFO 0010000 fifo | |
167 S_ISUID 0004000 set UID bit | |
168 S_ISGID 0002000 set GID bit (see below) | |
169 S_ISVTX 0001000 sticky bit (see below) | |
170 | |
171 Access: | |
172 S_IRWXU 00700 mask for file owner permissions | |
173 S_IRUSR 00400 owner has read permission | |
174 S_IWUSR 00200 owner has write permission | |
175 S_IXUSR 00100 owner has execute permission | |
176 S_IRWXG 00070 mask for group permissions | |
177 S_IRGRP 00040 group has read permission | |
178 S_IWGRP 00020 group has write permission | |
179 S_IXGRP 00010 group has execute permission | |
180 S_IRWXO 00007 mask for permissions for others (not in group) | |
181 S_IROTH 00004 others have read permission | |
182 S_IWOTH 00002 others have write permisson | |
183 S_IXOTH 00001 others have execute permission | |
184 */ | |
185 | |
186 void FileAccess::setUdsEntry( const KIO::UDSEntry& e ) | |
187 { | |
188 #ifndef KREPLACEMENTS_H | |
189 KIO::UDSEntry::const_iterator ei; | |
190 long acc = 0; | |
191 long fileType = 0; | |
192 for( ei=e.begin(); ei!=e.end(); ++ei ) | |
193 { | |
194 const KIO::UDSAtom& a = *ei; | |
195 switch( a.m_uds ) | |
196 { | |
197 case KIO::UDS_SIZE : m_size = a.m_long; break; | |
198 case KIO::UDS_USER : m_user = a.m_str; break; | |
199 case KIO::UDS_GROUP : m_group = a.m_str; break; | |
200 case KIO::UDS_NAME : m_path = a.m_str; break; // During listDir the relative path is given here. | |
201 case KIO::UDS_MODIFICATION_TIME : m_modificationTime.setTime_t( a.m_long ); break; | |
202 case KIO::UDS_ACCESS_TIME : m_accessTime.setTime_t( a.m_long ); break; | |
203 case KIO::UDS_CREATION_TIME : m_creationTime.setTime_t( a.m_long ); break; | |
204 case KIO::UDS_LINK_DEST : m_linkTarget = a.m_str; break; | |
205 case KIO::UDS_ACCESS : | |
206 { | |
207 acc = a.m_long; | |
208 m_bReadable = (acc & S_IRUSR)!=0; | |
209 m_bWritable = (acc & S_IWUSR)!=0; | |
210 m_bExecutable = (acc & S_IXUSR)!=0; | |
211 break; | |
212 } | |
213 case KIO::UDS_FILE_TYPE : | |
214 { | |
215 fileType = a.m_long; | |
216 m_bDir = ( fileType & S_IFMT ) == S_IFDIR; | |
217 m_bFile = ( fileType & S_IFMT ) == S_IFREG; | |
218 m_bSymLink = ( fileType & S_IFMT ) == S_IFLNK; | |
219 m_bExists = fileType != 0; | |
220 m_fileType = fileType; | |
221 break; | |
222 } | |
223 | |
224 case KIO::UDS_URL : // m_url = KURL( a.str ); | |
225 break; | |
226 case KIO::UDS_MIME_TYPE : break; | |
227 case KIO::UDS_GUESSED_MIME_TYPE : break; | |
228 case KIO::UDS_XML_PROPERTIES : break; | |
229 default: break; | |
230 } | |
231 } | |
232 | |
233 m_bExists = acc!=0 || fileType!=0; | |
234 | |
235 m_bLocal = false; | |
236 m_bValidData = true; | |
237 m_bSymLink = !m_linkTarget.isEmpty(); | |
238 if ( m_name.isEmpty() ) | |
239 { | |
240 int pos = m_path.findRev('/') + 1; | |
241 m_name = m_path.mid( pos ); | |
242 } | |
243 m_bHidden = m_name[0]=='.'; | |
244 #endif | |
245 } | |
246 | |
247 | |
248 bool FileAccess::isValid() const { return m_bValidData; } | |
249 bool FileAccess::isFile() const { return m_bFile; } | |
250 bool FileAccess::isDir() const { return m_bDir; } | |
251 bool FileAccess::isSymLink() const { return m_bSymLink; } | |
252 bool FileAccess::exists() const { return m_bExists; } | |
253 long FileAccess::size() const { return m_size; } | |
254 KURL FileAccess::url() const { return m_url; } | |
255 bool FileAccess::isLocal() const { return m_bLocal; } | |
256 bool FileAccess::isReadable() const { return m_bReadable; } | |
257 bool FileAccess::isWritable() const { return m_bWritable; } | |
258 bool FileAccess::isExecutable() const { return m_bExecutable; } | |
259 bool FileAccess::isHidden() const { return m_bHidden; } | |
260 QString FileAccess::readLink() const { return m_linkTarget; } | |
261 QString FileAccess::absFilePath() const{ return m_absFilePath; } // Full abs path | |
262 QString FileAccess::fileName() const { return m_name; } // Just the name-part of the path, without parent directories | |
263 QString FileAccess::filePath() const { return m_path; } // The path-string that was used during construction | |
264 QString FileAccess::prettyAbsPath() const { return isLocal() ? m_absFilePath : m_url.prettyURL(); } | |
265 | |
266 QDateTime FileAccess::created() const | |
267 { | |
268 return ( m_creationTime.isValid() ? m_creationTime : m_modificationTime ); | |
269 } | |
270 | |
271 QDateTime FileAccess::lastModified() const | |
272 { | |
273 return m_modificationTime; | |
274 } | |
275 | |
276 QDateTime FileAccess::lastRead() const | |
277 { | |
278 return ( m_accessTime.isValid() ? m_accessTime : m_modificationTime ); | |
279 } | |
280 | |
281 static bool interruptableReadFile( QFile& f, void* pDestBuffer, unsigned long maxLength ) | |
282 { | |
283 const unsigned long maxChunkSize = 100000; | |
284 unsigned long i=0; | |
285 while( i<maxLength ) | |
286 { | |
287 unsigned long nextLength = min2( maxLength-i, maxChunkSize ); | |
288 unsigned long reallyRead = f.readBlock( (char*)pDestBuffer+i, nextLength ); | |
289 if ( reallyRead != nextLength ) | |
290 { | |
291 return false; | |
292 } | |
293 i+=reallyRead; | |
294 | |
295 g_pProgressDialog->setSubCurrent( double(i)/maxLength ); | |
296 if ( g_pProgressDialog->wasCancelled() ) return false; | |
297 } | |
298 return true; | |
299 } | |
300 | |
301 bool FileAccess::readFile( void* pDestBuffer, unsigned long maxLength ) | |
302 { | |
303 if ( !m_localCopy.isEmpty() ) | |
304 { | |
305 QFile f( m_localCopy ); | |
306 if ( f.open( IO_ReadOnly ) ) | |
307 return interruptableReadFile(f, pDestBuffer, maxLength);// maxLength == f.readBlock( (char*)pDestBuffer, maxLength ); | |
308 } | |
309 else if (m_bLocal) | |
310 { | |
311 QFile f( filePath() ); | |
312 | |
313 if ( f.open( IO_ReadOnly ) ) | |
314 return interruptableReadFile(f, pDestBuffer, maxLength); //maxLength == f.readBlock( (char*)pDestBuffer, maxLength ); | |
315 } | |
316 else | |
317 { | |
318 FileAccessJobHandler jh( this ); | |
319 return jh.get( pDestBuffer, maxLength ); | |
320 } | |
321 return false; | |
322 } | |
323 | |
324 bool FileAccess::writeFile( void* pSrcBuffer, unsigned long length ) | |
325 { | |
326 if (m_bLocal) | |
327 { | |
328 QFile f( filePath() ); | |
329 if ( f.open( IO_WriteOnly ) ) | |
330 { | |
331 const unsigned long maxChunkSize = 100000; | |
332 unsigned long i=0; | |
333 while( i<length ) | |
334 { | |
335 unsigned long nextLength = min2( length-i, maxChunkSize ); | |
336 unsigned long reallyWritten = f.writeBlock( (char*)pSrcBuffer+i, nextLength ); | |
337 if ( reallyWritten != nextLength ) | |
338 { | |
339 return false; | |
340 } | |
341 i+=reallyWritten; | |
342 | |
343 g_pProgressDialog->setSubCurrent( double(i)/length ); | |
344 if ( g_pProgressDialog->wasCancelled() ) return false; | |
345 } | |
346 return true; | |
347 } | |
348 } | |
349 else | |
350 { | |
351 FileAccessJobHandler jh( this ); | |
352 return jh.put( pSrcBuffer, length, true /*overwrite*/ ); | |
353 } | |
354 return false; | |
355 } | |
356 | |
357 bool FileAccess::copyFile( const QString& dest ) | |
358 { | |
359 FileAccessJobHandler jh( this ); | |
360 return jh.copyFile( dest ); // Handles local and remote copying. | |
361 } | |
362 | |
363 bool FileAccess::rename( const QString& dest ) | |
364 { | |
365 FileAccessJobHandler jh( this ); | |
366 return jh.rename( dest ); | |
367 } | |
368 | |
369 bool FileAccess::removeFile() | |
370 { | |
371 if ( isLocal() ) | |
372 { | |
373 return QDir().remove( absFilePath() ); | |
374 } | |
375 else | |
376 { | |
377 FileAccessJobHandler jh( this ); | |
378 return jh.removeFile( absFilePath() ); | |
379 } | |
380 } | |
381 | |
382 bool FileAccess::removeFile( const QString& name ) // static | |
383 { | |
384 return FileAccess(name).removeFile(); | |
385 } | |
386 | |
387 bool FileAccess::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, | |
388 const QString& filePattern, const QString& fileAntiPattern, const QString& dirAntiPattern, | |
389 bool bFollowDirLinks, bool bUseCvsIgnore ) | |
390 { | |
391 FileAccessJobHandler jh( this ); | |
392 return jh.listDir( pDirList, bRecursive, bFindHidden, filePattern, fileAntiPattern, | |
393 dirAntiPattern, bFollowDirLinks, bUseCvsIgnore ); | |
394 } | |
395 | |
396 QString FileAccess::tempFileName() | |
397 { | |
398 #ifdef KREPLACEMENTS_H | |
399 | |
400 QString fileName; | |
401 #ifdef _WIN32 | |
402 QString tmpDir = getenv("TEMP"); | |
403 for(int i=0; ;++i) | |
404 { | |
405 // short filenames for WIN98 because for system() the command must not exceed 120 characters. | |
406 fileName = tmpDir + "/" + QString::number(i); | |
407 if ( ! FileAccess::exists(fileName) ) | |
408 break; | |
409 } | |
410 #else | |
411 QString tmpDir = "/tmp"; | |
412 for(int i=0; ;++i) | |
413 { | |
414 fileName = tmpDir + "/kdiff3_" + QString::number(i) +".tmp"; | |
415 if ( ! FileAccess::exists(fileName) ) | |
416 break; | |
417 } | |
418 #endif | |
419 | |
420 return QDir::convertSeparators(fileName); | |
421 | |
422 #else // using KDE | |
423 | |
424 KTempFile tmpFile; | |
425 tmpFile.setAutoDelete( true ); // We only want the name. Delete the precreated file immediately. | |
426 return tmpFile.name(); | |
427 | |
428 #endif | |
429 } | |
430 | |
431 bool FileAccess::makeDir( const QString& dirName ) | |
432 { | |
433 FileAccessJobHandler fh(0); | |
434 return fh.mkDir( dirName ); | |
435 } | |
436 | |
437 bool FileAccess::removeDir( const QString& dirName ) | |
438 { | |
439 FileAccessJobHandler fh(0); | |
440 return fh.rmDir( dirName ); | |
441 } | |
442 | |
443 bool FileAccess::symLink( const QString& linkTarget, const QString& linkLocation ) | |
444 { | |
445 return 0==::symlink( linkTarget.ascii(), linkLocation.ascii() ); | |
446 //FileAccessJobHandler fh(0); | |
447 //return fh.symLink( linkTarget, linkLocation ); | |
448 } | |
449 | |
450 bool FileAccess::exists( const QString& name ) | |
451 { | |
452 FileAccess fa( name ); | |
453 return fa.exists(); | |
454 } | |
455 | |
456 // If the size couldn't be determined by stat() then the file is copied to a local temp file. | |
457 long FileAccess::sizeForReading() | |
458 { | |
459 if ( m_size == 0 && !isLocal() ) | |
460 { | |
461 // Size couldn't be determined. Copy the file to a local temp place. | |
462 QString localCopy = tempFileName(); | |
463 bool bSuccess = copyFile( localCopy ); | |
464 if ( bSuccess ) | |
465 { | |
466 QFileInfo fi( localCopy ); | |
467 m_size = fi.size(); | |
468 m_localCopy = localCopy; | |
469 return m_size; | |
470 } | |
471 else | |
472 { | |
473 return 0; | |
474 } | |
475 } | |
476 else | |
477 return m_size; | |
478 } | |
479 | |
480 QString FileAccess::getStatusText() | |
481 { | |
482 return m_statusText; | |
483 } | |
484 | |
485 QString FileAccess::cleanDirPath( const QString& path ) // static | |
486 { | |
487 KURL url(path); | |
488 if ( url.isLocalFile() || ! url.isValid() ) | |
489 { | |
490 return QDir().cleanDirPath( path ); | |
491 } | |
492 else | |
493 { | |
494 return path; | |
495 } | |
496 } | |
497 | |
498 bool FileAccess::createBackup( const QString& bakExtension ) | |
499 { | |
500 if ( exists() ) | |
501 { | |
502 // First rename the existing file to the bak-file. If a bak-file file exists, delete that. | |
503 QString bakName = absFilePath() + bakExtension; | |
504 FileAccess bakFile( bakName, true /*bWantToWrite*/ ); | |
505 if ( bakFile.exists() ) | |
506 { | |
507 bool bSuccess = bakFile.removeFile(); | |
508 if ( !bSuccess ) | |
509 { | |
510 m_statusText = i18n("While trying to make a backup, deleting an older backup failed. \nFilename: ") + bakName; | |
511 return false; | |
512 } | |
513 } | |
514 bool bSuccess = rename( bakName ); | |
515 if (!bSuccess) | |
516 { | |
517 m_statusText = i18n("While trying to make a backup, renaming failed. \nFilenames: ") + | |
518 absFilePath() + " -> " + bakName; | |
519 return false; | |
520 } | |
521 } | |
522 return true; | |
523 } | |
524 | |
525 FileAccessJobHandler::FileAccessJobHandler( FileAccess* pFileAccess ) | |
526 { | |
527 m_pFileAccess = pFileAccess; | |
528 m_bSuccess = false; | |
529 } | |
530 | |
531 bool FileAccessJobHandler::stat( int detail, bool bWantToWrite ) | |
532 { | |
533 m_bSuccess = false; | |
534 m_pFileAccess->m_statusText = QString(); | |
535 KIO::StatJob* pStatJob = KIO::stat( m_pFileAccess->m_url, ! bWantToWrite, detail, false ); | |
536 | |
537 connect( pStatJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotStatResult(KIO::Job*))); | |
538 | |
539 g_pProgressDialog->enterEventLoop(); | |
540 | |
541 return m_bSuccess; | |
542 } | |
543 | |
544 void FileAccessJobHandler::slotStatResult(KIO::Job* pJob) | |
545 { | |
546 if ( pJob->error() ) | |
547 { | |
548 //pJob->showErrorDialog(g_pProgressDialog); | |
549 m_pFileAccess->m_bExists = false; | |
550 m_bSuccess = true; | |
551 } | |
552 else | |
553 { | |
554 m_bSuccess = true; | |
555 | |
556 m_pFileAccess->m_bValidData = true; | |
557 const KIO::UDSEntry e = static_cast<KIO::StatJob*>(pJob)->statResult(); | |
558 | |
559 m_pFileAccess->setUdsEntry( e ); | |
560 } | |
561 | |
562 g_pProgressDialog->exitEventLoop(); | |
563 } | |
564 | |
565 | |
566 bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength ) | |
567 { | |
568 if ( maxLength>0 ) | |
569 { | |
570 KIO::TransferJob* pJob = KIO::get( m_pFileAccess->m_url, false /*reload*/, false ); | |
571 m_transferredBytes = 0; | |
572 m_pTransferBuffer = (char*)pDestBuffer; | |
573 m_maxLength = maxLength; | |
574 m_bSuccess = false; | |
575 m_pFileAccess->m_statusText = QString(); | |
576 | |
577 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
578 connect( pJob, SIGNAL(data(KIO::Job*,const QByteArray &)), this, SLOT(slotGetData(KIO::Job*, const QByteArray&))); | |
579 connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long))); | |
580 | |
581 g_pProgressDialog->enterEventLoop(); | |
582 return m_bSuccess; | |
583 } | |
584 else | |
585 return true; | |
586 } | |
587 | |
588 void FileAccessJobHandler::slotGetData( KIO::Job* pJob, const QByteArray& newData ) | |
589 { | |
590 if ( pJob->error() ) | |
591 { | |
592 pJob->showErrorDialog(g_pProgressDialog); | |
593 } | |
594 else | |
595 { | |
596 long length = min2( long(newData.size()), m_maxLength - m_transferredBytes ); | |
597 ::memcpy( m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size() ); | |
598 m_transferredBytes += length; | |
599 } | |
600 } | |
601 | |
602 bool FileAccessJobHandler::put(void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions ) | |
603 { | |
604 if ( maxLength>0 ) | |
605 { | |
606 KIO::TransferJob* pJob = KIO::put( m_pFileAccess->m_url, permissions, bOverwrite, bResume, false ); | |
607 m_transferredBytes = 0; | |
608 m_pTransferBuffer = (char*)pSrcBuffer; | |
609 m_maxLength = maxLength; | |
610 m_bSuccess = false; | |
611 m_pFileAccess->m_statusText = QString(); | |
612 | |
613 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotPutJobResult(KIO::Job*))); | |
614 connect( pJob, SIGNAL(dataReq(KIO::Job*, QByteArray&)), this, SLOT(slotPutData(KIO::Job*, QByteArray&))); | |
615 connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long))); | |
616 | |
617 g_pProgressDialog->enterEventLoop(); | |
618 return m_bSuccess; | |
619 } | |
620 else | |
621 return true; | |
622 } | |
623 | |
624 void FileAccessJobHandler::slotPutData( KIO::Job* pJob, QByteArray& data ) | |
625 { | |
626 if ( pJob->error() ) | |
627 { | |
628 pJob->showErrorDialog(g_pProgressDialog); | |
629 } | |
630 else | |
631 { | |
632 long maxChunkSize = 100000; | |
633 long length = min2( maxChunkSize, m_maxLength - m_transferredBytes ); | |
634 bool bSuccess = data.resize( length ); | |
635 if ( bSuccess ) | |
636 { | |
637 if ( length>0 ) | |
638 { | |
639 ::memcpy( data.data(), m_pTransferBuffer + m_transferredBytes, data.size() ); | |
640 m_transferredBytes += length; | |
641 } | |
642 } | |
643 else | |
644 { | |
645 KMessageBox::error( g_pProgressDialog, i18n("Out of memory") ); | |
646 data.resize(0); | |
647 m_bSuccess = false; | |
648 } | |
649 } | |
650 } | |
651 | |
652 void FileAccessJobHandler::slotPutJobResult(KIO::Job* pJob) | |
653 { | |
654 if ( pJob->error() ) | |
655 { | |
656 pJob->showErrorDialog(g_pProgressDialog); | |
657 } | |
658 else | |
659 { | |
660 m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition | |
661 } | |
662 g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec() | |
663 } | |
664 | |
665 bool FileAccessJobHandler::mkDir( const QString& dirName ) | |
666 { | |
667 KURL dirURL = KURL::fromPathOrURL( dirName ); | |
668 if ( dirName.isEmpty() ) | |
669 return false; | |
670 else if ( dirURL.isLocalFile() ) | |
671 { | |
672 return QDir().mkdir( dirURL.path() ); | |
673 } | |
674 else | |
675 { | |
676 m_bSuccess = false; | |
677 KIO::SimpleJob* pJob = KIO::mkdir( dirURL ); | |
678 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
679 | |
680 g_pProgressDialog->enterEventLoop(); | |
681 return m_bSuccess; | |
682 } | |
683 } | |
684 | |
685 bool FileAccessJobHandler::rmDir( const QString& dirName ) | |
686 { | |
687 KURL dirURL = KURL::fromPathOrURL( dirName ); | |
688 if ( dirName.isEmpty() ) | |
689 return false; | |
690 else if ( dirURL.isLocalFile() ) | |
691 { | |
692 return QDir().rmdir( dirURL.path() ); | |
693 } | |
694 else | |
695 { | |
696 m_bSuccess = false; | |
697 KIO::SimpleJob* pJob = KIO::rmdir( dirURL ); | |
698 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
699 | |
700 g_pProgressDialog->enterEventLoop(); | |
701 return m_bSuccess; | |
702 } | |
703 } | |
704 | |
705 bool FileAccessJobHandler::removeFile( const QString& fileName ) | |
706 { | |
707 if ( fileName.isEmpty() ) | |
708 return false; | |
709 else | |
710 { | |
711 m_bSuccess = false; | |
712 KIO::SimpleJob* pJob = KIO::file_delete( fileName, false ); | |
713 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
714 | |
715 g_pProgressDialog->enterEventLoop(); | |
716 return m_bSuccess; | |
717 } | |
718 } | |
719 | |
720 bool FileAccessJobHandler::symLink( const QString& linkTarget, const QString& linkLocation ) | |
721 { | |
722 if ( linkTarget.isEmpty() || linkLocation.isEmpty() ) | |
723 return false; | |
724 else | |
725 { | |
726 m_bSuccess = false; | |
727 KIO::CopyJob* pJob = KIO::link( linkTarget, linkLocation, false ); | |
728 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
729 | |
730 g_pProgressDialog->enterEventLoop(); | |
731 return m_bSuccess; | |
732 } | |
733 } | |
734 | |
735 bool FileAccessJobHandler::rename( const QString& dest ) | |
736 { | |
737 KURL kurl = KURL::fromPathOrURL( dest ); | |
738 if ( dest.isEmpty() ) | |
739 return false; | |
740 else if ( m_pFileAccess->isLocal() && kurl.isLocalFile() ) | |
741 { | |
742 return QDir().rename( m_pFileAccess->absFilePath(), kurl.path() ); | |
743 } | |
744 else | |
745 { | |
746 bool bOverwrite = false; | |
747 bool bResume = false; | |
748 bool bShowProgress = false; | |
749 int permissions=-1; | |
750 m_bSuccess = false; | |
751 KIO::FileCopyJob* pJob = KIO::file_move( m_pFileAccess->m_url, kurl.url(), permissions, bOverwrite, bResume, bShowProgress ); | |
752 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
753 connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long))); | |
754 | |
755 g_pProgressDialog->enterEventLoop(); | |
756 return m_bSuccess; | |
757 } | |
758 } | |
759 | |
760 void FileAccessJobHandler::slotSimpleJobResult(KIO::Job* pJob) | |
761 { | |
762 if ( pJob->error() ) | |
763 { | |
764 pJob->showErrorDialog(g_pProgressDialog); | |
765 } | |
766 else | |
767 { | |
768 m_bSuccess = true; | |
769 } | |
770 g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec() | |
771 } | |
772 | |
773 | |
774 // Copy local or remote files. | |
775 bool FileAccessJobHandler::copyFile( const QString& dest ) | |
776 { | |
777 KURL destUrl = KURL::fromPathOrURL( dest ); | |
778 m_pFileAccess->m_statusText = QString(); | |
779 if ( ! m_pFileAccess->isLocal() || ! destUrl.isLocalFile() ) // if either url is nonlocal | |
780 { | |
781 bool bOverwrite = false; | |
782 bool bResume = false; | |
783 bool bShowProgress = false; | |
784 int permissions = (m_pFileAccess->isExecutable()?0111:0)+(m_pFileAccess->isWritable()?0222:0)+(m_pFileAccess->isReadable()?0444:0); | |
785 m_bSuccess = false; | |
786 KIO::FileCopyJob* pJob = KIO::file_copy ( m_pFileAccess->m_url, destUrl.url(), permissions, bOverwrite, bResume, bShowProgress ); | |
787 connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*))); | |
788 connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long))); | |
789 g_pProgressDialog->enterEventLoop(); | |
790 | |
791 return m_bSuccess; | |
792 // Note that the KIO-slave preserves the original date, if this is supported. | |
793 } | |
794 | |
795 // Both files are local: | |
796 QString srcName = m_pFileAccess->absFilePath(); | |
797 QString destName = dest; | |
798 QFile srcFile( srcName ); | |
799 QFile destFile( destName ); | |
800 bool bReadSuccess = srcFile.open( IO_ReadOnly ); | |
801 if ( bReadSuccess == false ) | |
802 { | |
803 m_pFileAccess->m_statusText = "Error during file copy operation: Opening file for reading failed. Filename: " + srcName; | |
804 return false; | |
805 } | |
806 bool bWriteSuccess = destFile.open( IO_WriteOnly ); | |
807 if ( bWriteSuccess == false ) | |
808 { | |
809 m_pFileAccess->m_statusText = "Error during file copy operation: Opening file for writing failed. Filename: " + destName; | |
810 return false; | |
811 } | |
812 | |
813 #if QT_VERSION==230 | |
814 typedef long Q_LONG; | |
815 #endif | |
816 std::vector<char> buffer(100000); | |
817 Q_LONG bufSize = buffer.size(); | |
818 Q_LONG srcSize = srcFile.size(); | |
819 while ( srcSize > 0 ) | |
820 { | |
821 Q_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) ); | |
822 if ( readSize==-1 ) | |
823 { | |
824 m_pFileAccess->m_statusText = "Error during file copy operation: Reading failed. Filename: "+srcName; | |
825 return false; | |
826 } | |
827 srcSize -= readSize; | |
828 while ( readSize > 0 ) | |
829 { | |
830 Q_LONG writeSize = destFile.writeBlock( &buffer[0], readSize ); | |
831 if ( writeSize==-1 ) | |
832 { | |
833 m_pFileAccess->m_statusText = "Error during file copy operation: Writing failed. Filename: "+destName; | |
834 return false; | |
835 } | |
836 readSize -= writeSize; | |
837 } | |
838 destFile.flush(); | |
839 } | |
840 srcFile.close(); | |
841 destFile.close(); | |
842 | |
843 // Update the times of the destFile | |
844 #ifdef _WIN32 | |
845 struct _stat srcFileStatus; | |
846 int statResult = ::_stat( srcName.ascii(), &srcFileStatus ); | |
847 if (statResult==0) | |
848 { | |
849 _utimbuf destTimes; | |
850 destTimes.actime = srcFileStatus.st_atime;/* time of last access */ | |
851 destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ | |
852 | |
853 _utime ( destName.ascii(), &destTimes ); | |
854 _chmod ( destName.ascii(), srcFileStatus.st_mode ); | |
855 } | |
856 #else | |
857 struct stat srcFileStatus; | |
858 int statResult = ::stat( srcName.ascii(), &srcFileStatus ); | |
859 if (statResult==0) | |
860 { | |
861 utimbuf destTimes; | |
862 destTimes.actime = srcFileStatus.st_atime;/* time of last access */ | |
863 destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */ | |
864 | |
865 utime ( destName.ascii(), &destTimes ); | |
866 chmod ( destName.ascii(), srcFileStatus.st_mode ); | |
867 } | |
868 #endif | |
869 return true; | |
870 } | |
871 | |
872 static bool wildcardMultiMatch( const QString& wildcard, const QString& testString, bool bCaseSensitive ) | |
873 { | |
874 QStringList sl = QStringList::split( ";", wildcard ); | |
875 | |
876 for ( QStringList::Iterator it = sl.begin(); it != sl.end(); ++it ) | |
877 { | |
878 QRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/); | |
879 #if QT_VERSION==230 | |
880 int len=0; | |
881 if ( pattern.match( testString, 0, &len )!=-1 && len==testString.length()) | |
882 return true; | |
883 #else | |
884 if ( pattern.exactMatch( testString ) ) | |
885 return true; | |
886 #endif | |
887 } | |
888 | |
889 return false; | |
890 } | |
891 | |
892 | |
893 // class CvsIgnoreList from Cervisia cvsdir.cpp | |
894 // Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de> | |
895 // with elements from class StringMatcher | |
896 // Copyright (c) 2003 André Wöbbeking <Woebbeking@web.de> | |
897 // Modifications for KDiff3 by Joachim Eibl | |
898 class CvsIgnoreList | |
899 { | |
900 public: | |
901 CvsIgnoreList(){} | |
902 void init(FileAccess& dir, bool bUseLocalCvsIgnore ); | |
903 bool matches(const QString& fileName) const; | |
904 | |
905 private: | |
906 void addEntriesFromString(const QString& str); | |
907 void addEntriesFromFile(const QString& name); | |
908 void addEntry(const QString& entry); | |
909 | |
910 QStringList m_exactPatterns; | |
911 QStringList m_startPatterns; | |
912 QStringList m_endPatterns; | |
913 QStringList m_generalPatterns; | |
914 }; | |
915 | |
916 | |
917 void CvsIgnoreList::init( FileAccess& dir, bool bUseLocalCvsIgnore ) | |
918 { | |
919 static const char *ignorestr = ". .. core RCSLOG tags TAGS RCS SCCS .make.state " | |
920 ".nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj " | |
921 "*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$"; | |
922 | |
923 addEntriesFromString(QString::fromLatin1(ignorestr)); | |
924 addEntriesFromFile(QDir::homeDirPath() + "/.cvsignore"); | |
925 addEntriesFromString(QString::fromLocal8Bit(::getenv("CVSIGNORE"))); | |
926 | |
927 if (bUseLocalCvsIgnore) | |
928 { | |
929 FileAccess file(dir); | |
930 file.addPath( ".cvsignore" ); | |
931 int size = file.exists() ? file.sizeForReading() : 0; | |
932 if ( size>0 ) | |
933 { | |
934 char* buf=new char[size]; | |
935 if (buf!=0) | |
936 { | |
937 file.readFile( buf, size ); | |
938 int pos1 = 0; | |
939 for ( int pos = 0; pos<=size; ++pos ) | |
940 { | |
941 if( pos==size || buf[pos]==' ' || buf[pos]=='\t' || buf[pos]=='\n' || buf[pos]=='\r' ) | |
942 { | |
943 if (pos>pos1) | |
944 { | |
945 QCString entry( &buf[pos1], pos-pos1+1 ); | |
946 addEntry( entry ); | |
947 } | |
948 pos1=pos+1; | |
949 } | |
950 } | |
951 delete buf; | |
952 } | |
953 } | |
954 } | |
955 } | |
956 | |
957 | |
958 void CvsIgnoreList::addEntriesFromString(const QString& str) | |
959 { | |
960 int posLast(0); | |
961 int pos; | |
962 while ((pos = str.find(' ', posLast)) >= 0) | |
963 { | |
964 if (pos > posLast) | |
965 addEntry(str.mid(posLast, pos - posLast)); | |
966 posLast = pos + 1; | |
967 } | |
968 | |
969 if (posLast < static_cast<int>(str.length())) | |
970 addEntry(str.mid(posLast)); | |
971 } | |
972 | |
973 | |
974 void CvsIgnoreList::addEntriesFromFile(const QString &name) | |
975 { | |
976 QFile file(name); | |
977 | |
978 if( file.open(IO_ReadOnly) ) | |
979 { | |
980 QTextStream stream(&file); | |
981 while( !stream.eof() ) | |
982 { | |
983 addEntriesFromString(stream.readLine()); | |
984 } | |
985 } | |
986 } | |
987 | |
988 void CvsIgnoreList::addEntry(const QString& pattern) | |
989 { | |
990 if (pattern != QChar('!')) | |
991 { | |
992 if (pattern.isEmpty()) return; | |
993 | |
994 // The general match is general but slow. | |
995 // Special tests for '*' and '?' at the beginning or end of a pattern | |
996 // allow fast checks. | |
997 | |
998 // Count number of '*' and '?' | |
999 unsigned int nofMetaCharacters = 0; | |
1000 | |
1001 const QChar* pos; | |
1002 pos = pattern.unicode(); | |
1003 const QChar* posEnd; | |
1004 posEnd=pos + pattern.length(); | |
1005 while (pos < posEnd) | |
1006 { | |
1007 if( *pos==QChar('*') || *pos==QChar('?') ) ++nofMetaCharacters; | |
1008 ++pos; | |
1009 } | |
1010 | |
1011 if ( nofMetaCharacters==0 ) | |
1012 { | |
1013 m_exactPatterns.append(pattern); | |
1014 } | |
1015 else if ( nofMetaCharacters==1 ) | |
1016 { | |
1017 if ( pattern.constref(0) == QChar('*') ) | |
1018 { | |
1019 m_endPatterns.append( pattern.right( pattern.length() - 1) ); | |
1020 } | |
1021 else if (pattern.constref(pattern.length() - 1) == QChar('*')) | |
1022 { | |
1023 m_startPatterns.append( pattern.left( pattern.length() - 1) ); | |
1024 } | |
1025 else | |
1026 { | |
1027 m_generalPatterns.append(pattern.local8Bit()); | |
1028 } | |
1029 } | |
1030 else | |
1031 { | |
1032 m_generalPatterns.append(pattern.local8Bit()); | |
1033 } | |
1034 } | |
1035 else | |
1036 { | |
1037 m_exactPatterns.clear(); | |
1038 m_startPatterns.clear(); | |
1039 m_endPatterns.clear(); | |
1040 m_generalPatterns.clear(); | |
1041 } | |
1042 } | |
1043 | |
1044 bool CvsIgnoreList::matches(const QString& text) const | |
1045 { | |
1046 if (m_exactPatterns.find(text) != m_exactPatterns.end()) | |
1047 { | |
1048 return true; | |
1049 } | |
1050 | |
1051 QStringList::ConstIterator it; | |
1052 QStringList::ConstIterator itEnd; | |
1053 for ( it=m_startPatterns.begin(), itEnd=m_startPatterns.end(); it != itEnd; ++it) | |
1054 { | |
1055 if (text.startsWith(*it)) | |
1056 { | |
1057 return true; | |
1058 } | |
1059 } | |
1060 | |
1061 for ( it = m_endPatterns.begin(), itEnd=m_endPatterns.end(); it != itEnd; ++it) | |
1062 { | |
1063 if (text.mid( text.length() - (*it).length() )==*it) //(text.endsWith(*it)) | |
1064 { | |
1065 return true; | |
1066 } | |
1067 } | |
1068 | |
1069 /* | |
1070 for (QValueList<QCString>::const_iterator it(m_generalPatterns.begin()), | |
1071 itEnd(m_generalPatterns.end()); | |
1072 it != itEnd; ++it) | |
1073 { | |
1074 if (::fnmatch(*it, text.local8Bit(), FNM_PATHNAME) == 0) | |
1075 { | |
1076 return true; | |
1077 } | |
1078 } | |
1079 */ | |
1080 | |
1081 | |
1082 for ( it = m_generalPatterns.begin(); it != m_generalPatterns.end(); ++it ) | |
1083 { | |
1084 QRegExp pattern( *it, true /*CaseSensitive*/, true /*wildcard mode*/); | |
1085 #if QT_VERSION==230 | |
1086 int len=0; | |
1087 if ( pattern.match( text, 0, &len )!=-1 && len==text.length()) | |
1088 return true; | |
1089 #else | |
1090 if ( pattern.exactMatch( text ) ) | |
1091 return true; | |
1092 #endif | |
1093 } | |
1094 | |
1095 return false; | |
1096 } | |
1097 | |
1098 static QString nicePath( const QFileInfo& fi ) | |
1099 { | |
1100 QString fp = fi.filePath(); | |
1101 if ( fp.length()>2 && fp[0] == '.' && fp[1] == '/' ) | |
1102 { | |
1103 return fp.mid(2); | |
1104 } | |
1105 return fp; | |
1106 } | |
1107 | |
1108 static bool cvsIgnoreExists( t_DirectoryList* pDirList ) | |
1109 { | |
1110 t_DirectoryList::iterator i; | |
1111 for( i = pDirList->begin(); i!=pDirList->end(); ++i ) | |
1112 { | |
1113 if ( i->fileName()==".cvsignore" ) | |
1114 return true; | |
1115 } | |
1116 return false; | |
1117 } | |
1118 | |
1119 bool FileAccessJobHandler::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, const QString& filePattern, | |
1120 const QString& fileAntiPattern, const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore ) | |
1121 { | |
1122 m_pDirList = pDirList; | |
1123 m_pDirList->clear(); | |
1124 m_bFindHidden = bFindHidden; | |
1125 m_bRecursive = bRecursive; | |
1126 m_bFollowDirLinks = bFollowDirLinks; // Only relevant if bRecursive==true. | |
1127 m_fileAntiPattern = fileAntiPattern; | |
1128 m_filePattern = filePattern; | |
1129 m_dirAntiPattern = dirAntiPattern; | |
1130 | |
1131 if ( g_pProgressDialog->wasCancelled() ) | |
1132 return true; // Cancelled is not an error. | |
1133 | |
1134 g_pProgressDialog->setSubInformation( i18n("Reading directory: ") + m_pFileAccess->absFilePath(), 0, false ); | |
1135 | |
1136 if( m_pFileAccess->isLocal() ) | |
1137 { | |
1138 m_bSuccess = QDir::setCurrent( m_pFileAccess->absFilePath() ); | |
1139 if ( m_bSuccess ) | |
1140 { | |
1141 m_bSuccess = true; | |
1142 QDir dir( "." ); | |
1143 | |
1144 dir.setSorting( QDir::Name | QDir::DirsFirst ); | |
1145 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden ); | |
1146 dir.setMatchAllDirs( true ); | |
1147 | |
1148 const QFileInfoList *fiList = dir.entryInfoList(); | |
1149 if ( fiList == 0 ) | |
1150 { | |
1151 // No Permission to read directory or other error. | |
1152 m_bSuccess = false; | |
1153 } | |
1154 else | |
1155 { | |
1156 QFileInfoListIterator it( *fiList ); // create list iterator | |
1157 for ( ; it.current() != 0; ++it ) // for each file... | |
1158 { | |
1159 QFileInfo* fi = it.current(); | |
1160 if ( fi->fileName() == "." || fi->fileName()==".." ) | |
1161 continue; | |
1162 | |
1163 pDirList->push_back( FileAccess( nicePath(*fi) ) ); | |
1164 } | |
1165 } | |
1166 } | |
1167 } | |
1168 else | |
1169 { | |
1170 bool bShowProgress = false; | |
1171 | |
1172 KIO::ListJob* pListJob=0; | |
1173 pListJob = KIO::listDir( m_pFileAccess->m_url, bShowProgress, true /*bFindHidden*/ ); | |
1174 | |
1175 m_bSuccess = false; | |
1176 if ( pListJob!=0 ) | |
1177 { | |
1178 connect( pListJob, SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList& ) ), | |
1179 this, SLOT( slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& )) ); | |
1180 connect( pListJob, SIGNAL( result( KIO::Job* )), | |
1181 this, SLOT( slotSimpleJobResult(KIO::Job*) ) ); | |
1182 | |
1183 connect( pListJob, SIGNAL( infoMessage(KIO::Job*, const QString&)), | |
1184 this, SLOT( slotListDirInfoMessage(KIO::Job*, const QString&) )); | |
1185 | |
1186 // This line makes the transfer via fish unreliable.:-( | |
1187 //connect( pListJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long))); | |
1188 | |
1189 g_pProgressDialog->enterEventLoop(); | |
1190 } | |
1191 } | |
1192 | |
1193 CvsIgnoreList cvsIgnoreList; | |
1194 if ( bUseCvsIgnore ) | |
1195 { | |
1196 cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) ); | |
1197 } | |
1198 | |
1199 // Now remove all entries that don't match: | |
1200 t_DirectoryList::iterator i; | |
1201 for( i = pDirList->begin(); i!=pDirList->end(); ) | |
1202 { | |
1203 t_DirectoryList::iterator i2=i; | |
1204 ++i2; | |
1205 QString fn = i->fileName(); | |
1206 if ( (!bFindHidden && i->isHidden() ) | |
1207 || | |
1208 (i->isFile() && | |
1209 ( !wildcardMultiMatch( filePattern, i->fileName(), true ) || | |
1210 wildcardMultiMatch( fileAntiPattern, i->fileName(), true ) ) ) | |
1211 || | |
1212 (i->isDir() && wildcardMultiMatch( dirAntiPattern, i->fileName(), true ) ) | |
1213 || | |
1214 cvsIgnoreList.matches(i->fileName()) | |
1215 ) | |
1216 { | |
1217 // Remove it | |
1218 pDirList->erase( i ); | |
1219 i = i2; | |
1220 } | |
1221 else | |
1222 { | |
1223 ++i; | |
1224 } | |
1225 } | |
1226 | |
1227 if ( bRecursive ) | |
1228 { | |
1229 t_DirectoryList subDirsList; | |
1230 | |
1231 t_DirectoryList::iterator i; | |
1232 for( i = m_pDirList->begin(); i!=m_pDirList->end(); ++i ) | |
1233 { | |
1234 if ( i->isDir() && (!i->isSymLink() || m_bFollowDirLinks)) | |
1235 { | |
1236 t_DirectoryList dirList; | |
1237 i->listDir( &dirList, bRecursive, bFindHidden, | |
1238 filePattern, fileAntiPattern, dirAntiPattern, bFollowDirLinks, bUseCvsIgnore ); | |
1239 | |
1240 t_DirectoryList::iterator j; | |
1241 for( j = dirList.begin(); j!=dirList.end(); ++j ) | |
1242 { | |
1243 j->m_path = i->fileName() + "/" + j->m_path; | |
1244 } | |
1245 | |
1246 // append data onto the main list | |
1247 subDirsList.splice( subDirsList.end(), dirList ); | |
1248 } | |
1249 } | |
1250 | |
1251 m_pDirList->splice( m_pDirList->end(), subDirsList ); | |
1252 } | |
1253 | |
1254 return m_bSuccess; | |
1255 } | |
1256 | |
1257 | |
1258 // Return value false means that the directory or some subdirectories | |
1259 // were not readable. Probably because of missing permissions. | |
1260 bool FileAccessJobHandler::scanLocalDirectory( const QString& dirName, t_DirectoryList* pDirList ) | |
1261 { | |
1262 bool bSuccess = true; | |
1263 QDir dir( dirName ); | |
1264 g_pProgressDialog->setInformation( "Scanning directory: " + dirName, 0, false ); | |
1265 | |
1266 // First search subdirectorys | |
1267 bool bHidden = m_bFindHidden; | |
1268 dir.setSorting( QDir::Name | QDir::DirsFirst ); | |
1269 dir.setFilter( QDir::Dirs | (bHidden ? QDir::Hidden : 0) ); | |
1270 dir.setMatchAllDirs( true ); | |
1271 | |
1272 const QFileInfoList *fiList = dir.entryInfoList(); | |
1273 if ( fiList == 0 ) | |
1274 { | |
1275 // No Permission to read directory or other error. | |
1276 return false; | |
1277 } | |
1278 | |
1279 QFileInfoListIterator it( *fiList ); // create list iterator | |
1280 | |
1281 for ( ; it.current() != 0; ++it ) // for each file... | |
1282 { | |
1283 if ( g_pProgressDialog->wasCancelled() ) | |
1284 return true; | |
1285 | |
1286 QFileInfo *fi = it.current(); | |
1287 if ( fi->isDir() ) | |
1288 { | |
1289 if ( fi->fileName() == "." || fi->fileName()==".." || | |
1290 wildcardMultiMatch( m_dirAntiPattern, fi->fileName(), true/*case sensitive*/ ) ) | |
1291 continue; | |
1292 else | |
1293 { | |
1294 if ( m_bRecursive ) | |
1295 if ( ! fi->isSymLink() || m_bFollowDirLinks ) | |
1296 { | |
1297 bool bLocalSuccess = scanLocalDirectory( fi->filePath(), pDirList ); | |
1298 if ( ! bLocalSuccess ) | |
1299 bSuccess = false; | |
1300 } | |
1301 } | |
1302 } | |
1303 } | |
1304 | |
1305 dir.setFilter( QDir::Files | QDir::Dirs | (bHidden ? QDir::Hidden : 0) ); | |
1306 dir.setMatchAllDirs( true ); | |
1307 dir.setNameFilter( m_filePattern ); | |
1308 | |
1309 fiList = dir.entryInfoList(); | |
1310 it = *fiList; | |
1311 | |
1312 QString sizeString; | |
1313 | |
1314 for ( ; it.current() != 0; ++it ) // for each file... | |
1315 { | |
1316 QFileInfo* fi = it.current(); | |
1317 | |
1318 if ( fi->fileName() == "." || fi->fileName()==".." || | |
1319 wildcardMultiMatch( fi->isDir() ? m_dirAntiPattern : m_fileAntiPattern, fi->fileName(), true/*case sensitive*/ ) ) | |
1320 continue; | |
1321 | |
1322 pDirList->push_back( FileAccess( nicePath(*fi) ) ); | |
1323 } | |
1324 return bSuccess; | |
1325 } | |
1326 | |
1327 void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l ) | |
1328 { | |
1329 KURL parentUrl( m_pFileAccess->m_absFilePath ); | |
1330 | |
1331 KIO::UDSEntryList::ConstIterator i; | |
1332 for ( i=l.begin(); i!=l.end(); ++i ) | |
1333 { | |
1334 const KIO::UDSEntry& e = *i; | |
1335 FileAccess fa; | |
1336 fa.setUdsEntry( e ); | |
1337 | |
1338 if ( fa.filePath() != "." && fa.filePath() != ".." ) | |
1339 { | |
1340 fa.m_url = parentUrl; | |
1341 fa.m_url.addPath( fa.filePath() ); | |
1342 fa.m_absFilePath = fa.m_url.url(); | |
1343 m_pDirList->push_back( fa ); | |
1344 } | |
1345 } | |
1346 } | |
1347 | |
1348 void FileAccessJobHandler::slotListDirInfoMessage( KIO::Job*, const QString& msg ) | |
1349 { | |
1350 g_pProgressDialog->setSubInformation( msg, 0 ); | |
1351 } | |
1352 | |
1353 void FileAccessJobHandler::slotPercent( KIO::Job*, unsigned long percent ) | |
1354 { | |
1355 g_pProgressDialog->setSubCurrent( percent/100.0 ); | |
1356 } | |
1357 | |
1358 | |
1359 ProgressDialog::ProgressDialog( QWidget* pParent ) | |
1360 : QDialog( pParent, 0, true ) | |
1361 { | |
1362 QVBoxLayout* layout = new QVBoxLayout(this); | |
1363 | |
1364 m_pInformation = new QLabel( " ", this ); | |
1365 layout->addWidget( m_pInformation ); | |
1366 | |
1367 m_pProgressBar = new KProgress(1000, this); | |
1368 layout->addWidget( m_pProgressBar ); | |
1369 | |
1370 m_pSubInformation = new QLabel( " ", this); | |
1371 layout->addWidget( m_pSubInformation ); | |
1372 | |
1373 m_pSubProgressBar = new KProgress(1000, this); | |
1374 layout->addWidget( m_pSubProgressBar ); | |
1375 | |
1376 m_dCurrent = 0.0; | |
1377 m_dSubMax = 1.0; | |
1378 m_dSubMin = 0.0; | |
1379 m_dSubCurrent = 0.0; | |
1380 resize( 400, 100 ); | |
1381 m_t1.start(); | |
1382 m_t2.start(); | |
1383 m_bWasCancelled = false; | |
1384 } | |
1385 | |
1386 | |
1387 void ProgressDialog::setInformation(const QString& info, double dCurrent, bool bRedrawUpdate ) | |
1388 { | |
1389 m_pInformation->setText( info ); | |
1390 m_dCurrent = dCurrent; | |
1391 m_dSubCurrent=0; | |
1392 m_dSubMin = 0; | |
1393 m_dSubMax = 1; | |
1394 m_pSubInformation->setText(""); | |
1395 recalc(bRedrawUpdate); | |
1396 } | |
1397 | |
1398 void ProgressDialog::setInformation(const QString& info, bool bRedrawUpdate ) | |
1399 { | |
1400 m_pInformation->setText( info ); | |
1401 m_dSubCurrent = 0; | |
1402 m_dSubMin = 0; | |
1403 m_dSubMax = 1; | |
1404 m_pSubInformation->setText(""); | |
1405 recalc(bRedrawUpdate); | |
1406 } | |
1407 | |
1408 void ProgressDialog::setMaximum( int maximum ) | |
1409 { | |
1410 m_maximum = maximum; | |
1411 m_dCurrent = 0; | |
1412 } | |
1413 | |
1414 void ProgressDialog::step( bool bRedrawUpdate ) | |
1415 { | |
1416 m_dCurrent += 1.0/m_maximum; | |
1417 m_dSubCurrent=0; | |
1418 recalc(bRedrawUpdate); | |
1419 } | |
1420 | |
1421 void ProgressDialog::setSubInformation(const QString& info, double dSubCurrent, bool bRedrawUpdate ) | |
1422 { | |
1423 m_pSubInformation->setText(info); | |
1424 m_dSubCurrent = dSubCurrent; | |
1425 recalc(bRedrawUpdate); | |
1426 } | |
1427 | |
1428 void ProgressDialog::setSubCurrent( double dSubCurrent, bool bRedrawUpdate ) | |
1429 { | |
1430 m_dSubCurrent = dSubCurrent; | |
1431 recalc( bRedrawUpdate ); | |
1432 } | |
1433 | |
1434 | |
1435 void qt_enter_modal(QWidget*); | |
1436 void qt_leave_modal(QWidget*); | |
1437 | |
1438 void ProgressDialog::enterEventLoop() | |
1439 { | |
1440 // instead of using exec() the eventloop is entered and exited often without hiding/showing the window. | |
1441 #if QT_VERSION==230 | |
1442 //qApp->enter_loop(); | |
1443 #else | |
1444 qt_enter_modal(this); | |
1445 qApp->eventLoop()->enterLoop(); | |
1446 qt_leave_modal(this); | |
1447 #endif | |
1448 } | |
1449 | |
1450 void ProgressDialog::exitEventLoop() | |
1451 { | |
1452 #if QT_VERSION==230 | |
1453 //qApp->exit_loop(); | |
1454 #else | |
1455 qApp->eventLoop()->exitLoop(); | |
1456 #endif | |
1457 } | |
1458 | |
1459 void ProgressDialog::recalc( bool bUpdate ) | |
1460 { | |
1461 if( (bUpdate && m_dSubCurrent == 0) || m_t1.elapsed()>200 ) | |
1462 { | |
1463 m_pProgressBar->setProgress( int( 1000.0 * m_dCurrent ) ); | |
1464 m_pSubProgressBar->setProgress( int( 1000.0 * ( m_dSubCurrent * (m_dSubMax - m_dSubMin) + m_dSubMin ) ) ); | |
1465 if ( !isVisible() ) show(); | |
1466 qApp->processEvents(); | |
1467 m_t1.restart(); | |
1468 } | |
1469 } | |
1470 | |
1471 void ProgressDialog::start() | |
1472 { | |
1473 setInformation("",0, true); | |
1474 setSubInformation("",0); | |
1475 m_bWasCancelled = false; | |
1476 m_t1.restart(); | |
1477 m_t2.restart(); | |
1478 show(); | |
1479 } | |
1480 | |
1481 #include <qtimer.h> | |
1482 void ProgressDialog::show() | |
1483 { | |
1484 #if QT_VERSION==230 | |
1485 QWidget::show(); | |
1486 #else | |
1487 QDialog::show(); | |
1488 #endif | |
1489 } | |
1490 | |
1491 void ProgressDialog::hide() | |
1492 { | |
1493 // Calling QDialog::hide() directly doesn't always work. (?) | |
1494 QTimer::singleShot( 100, this, SLOT(delayedHide()) ); | |
1495 } | |
1496 | |
1497 void ProgressDialog::delayedHide() | |
1498 { | |
1499 QDialog::hide(); | |
1500 } | |
1501 | |
1502 void ProgressDialog::reject() | |
1503 { | |
1504 m_bWasCancelled = true; | |
1505 QDialog::reject(); | |
1506 } | |
1507 | |
1508 bool ProgressDialog::wasCancelled() | |
1509 { | |
1510 if( m_t2.elapsed()>100 ) | |
1511 { | |
1512 qApp->processEvents(); | |
1513 m_t2.restart(); | |
1514 } | |
1515 return m_bWasCancelled; | |
1516 } | |
1517 | |
1518 // The progressbar goes from 0 to 1 usually. | |
1519 // By supplying a subrange transformation the subCurrent-values | |
1520 // 0 to 1 will be transformed to dMin to dMax instead. | |
1521 // Requirement: 0 < dMin < dMax < 1 | |
1522 void ProgressDialog::setSubRangeTransformation( double dMin, double dMax ) | |
1523 { | |
1524 m_dSubMin = dMin; | |
1525 m_dSubMax = dMax; | |
1526 m_dSubCurrent = 0; | |
1527 } | |
1528 | |
1529 | |
1530 #include "fileaccess.moc" |