You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kdiff3/src/fileaccess.cpp

1793 lines
53 KiB

/***************************************************************************
* Copyright (C) 2003 by Joachim Eibl *
* joachim.eibl at gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "fileaccess.h"
#include <iostream>
#include <cstdlib>
#include <kio/global.h>
#include <kmessagebox.h>
#include "optiondialog.h"
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqapplication.h>
#include <tqpushbutton.h>
#include <tqeventloop.h>
#include "common.h"
#include <ktempfile.h>
#include <tqdir.h>
#include <tqregexp.h>
#include <tqtextstream.h>
#include <vector>
#include <klocale.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <sys/utime.h>
#include <io.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h> // Needed for creating symbolic links via symlink().
#include <utime.h>
#endif
ProgressDialog* g_pProgressDialog=0;
FileAccess::FileAccess( const TQString& name, bool bWantToWrite )
{
setFile( name, bWantToWrite );
}
FileAccess::FileAccess()
{
m_bValidData = false;
m_size = 0;
m_creationTime = TQDateTime();
m_accessTime = TQDateTime();
m_modificationTime = TQDateTime();
m_bReadable = false;
m_bWritable = false;
m_bExecutable = false;
m_bLocal = false;
m_bHidden = false;
m_bExists = false;
m_bFile = false;
m_bDir = false;
m_bSymLink = false;
}
FileAccess::~FileAccess()
{
if( !m_localCopy.isEmpty() )
{
removeTempFile( m_localCopy );
}
}
void FileAccess::setFile( const TQString& name, bool bWantToWrite )
{
m_url = KURL::fromPathOrURL( name );
m_bValidData = false;
m_size = 0;
m_creationTime = TQDateTime();
m_accessTime = TQDateTime();
m_modificationTime = TQDateTime();
m_bReadable = false;
m_bWritable = false;
m_bExecutable = false;
m_bHidden = false;
m_bExists = false;
m_bFile = false;
m_bDir = false;
m_bSymLink = false;
m_linkTarget = "";
m_fileType = -1;
m_bLocal = true;
// Note: Checking if the filename-string is empty is necessary for Win95/98/ME.
// The isFile() / isDir() queries would cause the program to crash.
// (This is a Win95-bug which has been corrected only in WinNT/2000/XP.)
if ( !name.isEmpty() )
{
// FileAccess tries to detect if the given name is an URL or a local file.
// This is a problem if the filename looks like an URL (i.e. contains a colon ':').
// e.g. "file:f.txt" is a valid filename.
// Most of the time it is sufficient to check if the file exists locally.
// 2 Problems remain:
// 1. When the local file exists and the remote location is wanted nevertheless. (unlikely)
// 2. When the local file doesn't exist and should be written to.
bool bExistsLocal = TQDir().exists(name);
if ( m_url.isLocalFile() || !m_url.isValid() || bExistsLocal ) // assuming that invalid means relative
{
TQString localName = name;
if ( !bExistsLocal && m_url.isLocalFile() && name.left(5).lower()=="file:" )
{
localName = m_url.path(); // I want the path without preceding "file:"
}
TQFileInfo fi( localName );
#if defined(TQ_WS_WIN)
// On some windows machines in a network this takes very long.
// and it's not so important anyway.
m_bReadable = true;
m_bWritable = true; // in certain situations this might become a problem though
m_bExecutable = false;
#else
m_bReadable = fi.isReadable();
m_bWritable = fi.isWritable();
m_bExecutable = fi.isExecutable();
#endif
m_creationTime = fi.created();
m_bHidden = fi.isHidden();
m_modificationTime = fi.lastModified();
m_accessTime = fi.lastRead();
m_size = fi.size();
m_bSymLink = fi.isSymLink();
m_bFile = fi.isFile();
m_bDir = fi.isDir();
m_bExists = fi.exists();
m_name = fi.fileName();
m_path = fi.filePath();
m_absFilePath= fi.absFilePath();
if ( m_bSymLink ) m_linkTarget = fi.readLink();
m_bLocal = true;
m_bValidData = true;
if ( ! m_url.isValid() )
{
m_url.setPath( m_absFilePath );
}
if ( !m_bExists && m_absFilePath.contains("@@") )
{
// Try reading a clearcase file
m_localCopy = FileAccess::tempFileName();
TQString cmd = "cleartool get -to \"" + m_localCopy + "\" \"" + m_absFilePath + "\"";
::system( cmd.local8Bit() );
TQFileInfo fi( m_localCopy );
#if defined(TQ_WS_WIN)
m_bReadable = true;//fi.isReadable();
m_bWritable = true;//fi.isWritable();
m_bExecutable = false;//fi.isExecutable();
#else
m_bReadable = fi.isReadable();
m_bWritable = fi.isWritable();
m_bExecutable = fi.isExecutable();
#endif
m_creationTime = fi.created();
m_bHidden = fi.isHidden();
m_modificationTime = fi.lastModified();
m_accessTime = fi.lastRead();
m_size = fi.size();
m_bSymLink = fi.isSymLink();
m_bFile = fi.isFile();
m_bDir = fi.isDir();
m_bExists = fi.exists();
}
}
else
{
m_absFilePath = name;
m_name = m_url.fileName();
m_bLocal = false;
FileAccessJobHandler jh( this ); // A friend, which writes to the parameters of this class!
jh.stat(2/*all details*/, bWantToWrite); // returns bSuccess, ignored
m_path = name;
m_bValidData = true; // After running stat() the variables are initialised
// and valid even if the file doesn't exist and the stat
// query failed.
}
}
}
void FileAccess::addPath( const TQString& txt )
{
if ( m_url.isValid() )
{
m_url.addPath( txt );
setFile( m_url.url() ); // reinitialise
}
else
{
TQString slash = (txt.isEmpty() || txt[0]=='/') ? "" : "/";
setFile( absFilePath() + slash + txt );
}
}
/* Filetype:
S_IFMT 0170000 bittqmask for the file type bitfields
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 fifo
S_ISUID 0004000 set UID bit
S_ISGID 0002000 set GID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
Access:
S_IRWXU 00700 tqmask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 tqmask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 tqmask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permisson
S_IXOTH 00001 others have execute permission
*/
#ifdef KREPLACEMENTS_H
void FileAccess::setUdsEntry( const KIO::UDSEntry& ){} // not needed if KDE is not available
#else
void FileAccess::setUdsEntry( const KIO::UDSEntry& e )
{
KIO::UDSEntry::const_iterator ei;
long acc = 0;
long fileType = 0;
for( ei=e.begin(); ei!=e.end(); ++ei )
{
const KIO::UDSAtom& a = *ei;
switch( a.m_uds )
{
case KIO::UDS_SIZE : m_size = a.m_long; break;
case KIO::UDS_USER : m_user = a.m_str; break;
case KIO::UDS_GROUP : m_group = a.m_str; break;
case KIO::UDS_NAME : m_path = a.m_str; break; // During listDir the relative path is given here.
case KIO::UDS_MODIFICATION_TIME : m_modificationTime.setTime_t( a.m_long ); break;
case KIO::UDS_ACCESS_TIME : m_accessTime.setTime_t( a.m_long ); break;
case KIO::UDS_CREATION_TIME : m_creationTime.setTime_t( a.m_long ); break;
case KIO::UDS_LINK_DEST : m_linkTarget = a.m_str; break;
case KIO::UDS_ACCESS :
{
acc = a.m_long;
m_bReadable = (acc & S_IRUSR)!=0;
m_bWritable = (acc & S_IWUSR)!=0;
m_bExecutable = (acc & S_IXUSR)!=0;
break;
}
case KIO::UDS_FILE_TYPE :
{
fileType = a.m_long;
m_bDir = ( fileType & S_IFMT ) == S_IFDIR;
m_bFile = ( fileType & S_IFMT ) == S_IFREG;
m_bSymLink = ( fileType & S_IFMT ) == S_IFLNK;
m_bExists = fileType != 0;
m_fileType = fileType;
break;
}
case KIO::UDS_URL : // m_url = KURL( a.str );
break;
case KIO::UDS_MIME_TYPE : break;
case KIO::UDS_GUESSED_MIME_TYPE : break;
case KIO::UDS_XML_PROPERTIES : break;
default: break;
}
}
m_bExists = acc!=0 || fileType!=0;
m_bLocal = false;
m_bValidData = true;
m_bSymLink = !m_linkTarget.isEmpty();
if ( m_name.isEmpty() )
{
int pos = m_path.findRev('/') + 1;
m_name = m_path.mid( pos );
}
m_bHidden = m_name[0]=='.';
}
#endif
bool FileAccess::isValid() const { return m_bValidData; }
bool FileAccess::isFile() const { return m_bFile; }
bool FileAccess::isDir() const { return m_bDir; }
bool FileAccess::isSymLink() const { return m_bSymLink; }
bool FileAccess::exists() const { return m_bExists; }
long FileAccess::size() const { return m_size; }
KURL FileAccess::url() const { return m_url; }
bool FileAccess::isLocal() const { return m_bLocal; }
bool FileAccess::isReadable() const { return m_bReadable; }
bool FileAccess::isWritable() const { return m_bWritable; }
bool FileAccess::isExecutable() const { return m_bExecutable; }
bool FileAccess::isHidden() const { return m_bHidden; }
TQString FileAccess::readLink() const { return m_linkTarget; }
TQString FileAccess::absFilePath() const{ return m_absFilePath; } // Full abs path
TQString FileAccess::fileName() const { return m_name; } // Just the name-part of the path, without tqparent directories
TQString FileAccess::filePath() const { return m_path; } // The path-string that was used during construction
TQString FileAccess::prettyAbsPath() const { return isLocal() ? m_absFilePath : m_url.prettyURL(); }
TQDateTime FileAccess::created() const
{
return ( m_creationTime.isValid() ? m_creationTime : m_modificationTime );
}
TQDateTime FileAccess::lastModified() const
{
return m_modificationTime;
}
TQDateTime FileAccess::lastRead() const
{
return ( m_accessTime.isValid() ? m_accessTime : m_modificationTime );
}
static bool interruptableReadFile( TQFile& f, void* pDestBuffer, unsigned long maxLength )
{
ProgressProxy pp;
const unsigned long maxChunkSize = 100000;
unsigned long i=0;
while( i<maxLength )
{
unsigned long nextLength = min2( maxLength-i, maxChunkSize );
unsigned long reallyRead = f.readBlock( (char*)pDestBuffer+i, nextLength );
if ( reallyRead != nextLength )
{
return false;
}
i+=reallyRead;
pp.setCurrent( double(i)/maxLength );
if ( pp.wasCancelled() ) return false;
}
return true;
}
bool FileAccess::readFile( void* pDestBuffer, unsigned long maxLength )
{
if ( !m_localCopy.isEmpty() )
{
TQFile f( m_localCopy );
if ( f.open( IO_ReadOnly ) )
return interruptableReadFile(f, pDestBuffer, maxLength);// maxLength == f.readBlock( (char*)pDestBuffer, maxLength );
}
else if (m_bLocal)
{
TQFile f( filePath() );
if ( f.open( IO_ReadOnly ) )
return interruptableReadFile(f, pDestBuffer, maxLength); //maxLength == f.readBlock( (char*)pDestBuffer, maxLength );
}
else
{
FileAccessJobHandler jh( this );
return jh.get( pDestBuffer, maxLength );
}
return false;
}
bool FileAccess::writeFile( const void* pSrcBuffer, unsigned long length )
{
ProgressProxy pp;
if (m_bLocal)
{
TQFile f( filePath() );
if ( f.open( IO_WriteOnly ) )
{
const unsigned long maxChunkSize = 100000;
unsigned long i=0;
while( i<length )
{
unsigned long nextLength = min2( length-i, maxChunkSize );
unsigned long reallyWritten = f.writeBlock( (char*)pSrcBuffer+i, nextLength );
if ( reallyWritten != nextLength )
{
return false;
}
i+=reallyWritten;
pp.setCurrent( double(i)/length );
if ( pp.wasCancelled() ) return false;
}
f.close();
#ifndef _WIN32
if ( isExecutable() ) // value is true if the old file was executable
{
// Preserve attributes
struct stat srcFiletqStatus;
int statResult = ::stat( filePath().ascii(), &srcFiletqStatus );
if (statResult==0)
{
::chmod ( filePath().ascii(), srcFiletqStatus.st_mode | S_IXUSR );
}
}
#endif
return true;
}
}
else
{
FileAccessJobHandler jh( this );
return jh.put( pSrcBuffer, length, true /*overwrite*/ );
}
return false;
}
bool FileAccess::copyFile( const TQString& dest )
{
FileAccessJobHandler jh( this );
return jh.copyFile( dest ); // Handles local and remote copying.
}
bool FileAccess::rename( const TQString& dest )
{
FileAccessJobHandler jh( this );
return jh.rename( dest );
}
bool FileAccess::removeFile()
{
if ( isLocal() )
{
return TQDir().remove( absFilePath() );
}
else
{
FileAccessJobHandler jh( this );
return jh.removeFile( absFilePath() );
}
}
bool FileAccess::removeFile( const TQString& name ) // static
{
return FileAccess(name).removeFile();
}
bool FileAccess::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
const TQString& filePattern, const TQString& fileAntiPattern, const TQString& dirAntiPattern,
bool bFollowDirLinks, bool bUseCvsIgnore )
{
FileAccessJobHandler jh( this );
return jh.listDir( pDirList, bRecursive, bFindHidden, filePattern, fileAntiPattern,
dirAntiPattern, bFollowDirLinks, bUseCvsIgnore );
}
TQString FileAccess::tempFileName()
{
#ifdef KREPLACEMENTS_H
TQString fileName;
#ifdef _WIN32
TQString tmpDir = getenv("TEMP");
#else
TQString tmpDir = "/tmp";
#endif
for(int i=0; ;++i)
{
// short filenames for WIN98 because for system() the command must not exceed 120 characters.
#ifdef _WIN32
if ( TQApplication::winVersion() & TQt::WV_DOS_based ) // Win95, 98, ME
fileName = tmpDir + "\\" + TQString::number(i);
else
fileName = tmpDir + "/kdiff3_" + TQString::number(_getpid()) + "_" + TQString::number(i) +".tmp";
#else
fileName = tmpDir + "/kdiff3_" + TQString::number(getpid()) + "_" + TQString::number(i) +".tmp";
#endif
if ( ! FileAccess::exists(fileName) &&
TQFile(fileName).open(IO_WriteOnly) ) // open, truncate and close the file, true if successful
{
break;
}
}
return TQDir::convertSeparators(fileName+".2");
#else // using KDE
KTempFile tmpFile;
//tmpFile.setAutoDelete( true ); // We only want the name. Delete the precreated file immediately.
tmpFile.close();
return tmpFile.name()+".2";
#endif
}
bool FileAccess::removeTempFile( const TQString& name ) // static
{
if (name.endsWith(".2"))
FileAccess(name.left(name.length()-2)).removeFile();
return FileAccess(name).removeFile();
}
bool FileAccess::makeDir( const TQString& dirName )
{
FileAccessJobHandler fh(0);
return fh.mkDir( dirName );
}
bool FileAccess::removeDir( const TQString& dirName )
{
FileAccessJobHandler fh(0);
return fh.rmDir( dirName );
}
bool FileAccess::symLink( const TQString& linkTarget, const TQString& linkLocation )
{
#ifdef _WIN32
return false;
#else
return 0==::symlink( linkTarget.ascii(), linkLocation.ascii() );
//FileAccessJobHandler fh(0);
//return fh.symLink( linkTarget, linkLocation );
#endif
}
bool FileAccess::exists( const TQString& name )
{
FileAccess fa( name );
return fa.exists();
}
// If the size couldn't be determined by stat() then the file is copied to a local temp file.
long FileAccess::sizeForReading()
{
if ( m_size == 0 && !isLocal() )
{
// Size couldn't be determined. Copy the file to a local temp place.
TQString localCopy = tempFileName();
bool bSuccess = copyFile( localCopy );
if ( bSuccess )
{
TQFileInfo fi( localCopy );
m_size = fi.size();
m_localCopy = localCopy;
return m_size;
}
else
{
return 0;
}
}
else
return m_size;
}
TQString FileAccess::getStatusText()
{
return m_statusText;
}
TQString FileAccess::cleanDirPath( const TQString& path ) // static
{
KURL url(path);
if ( url.isLocalFile() || ! url.isValid() )
{
return TQDir().cleanDirPath( path );
}
else
{
return path;
}
}
bool FileAccess::createBackup( const TQString& bakExtension )
{
if ( exists() )
{
// First rename the existing file to the bak-file. If a bak-file file exists, delete that.
TQString bakName = absFilePath() + bakExtension;
FileAccess bakFile( bakName, true /*bWantToWrite*/ );
if ( bakFile.exists() )
{
bool bSuccess = bakFile.removeFile();
if ( !bSuccess )
{
m_statusText = i18n("While trying to make a backup, deleting an older backup failed. \nFilename: ") + bakName;
return false;
}
}
bool bSuccess = rename( bakName );
if (!bSuccess)
{
m_statusText = i18n("While trying to make a backup, renaming failed. \nFilenames: ") +
absFilePath() + " -> " + bakName;
return false;
}
}
return true;
}
FileAccessJobHandler::FileAccessJobHandler( FileAccess* pFileAccess )
{
m_pFileAccess = pFileAccess;
m_bSuccess = false;
}
bool FileAccessJobHandler::stat( int detail, bool bWantToWrite )
{
m_bSuccess = false;
m_pFileAccess->m_statusText = TQString();
KIO::StatJob* pStatJob = KIO::stat( m_pFileAccess->m_url, ! bWantToWrite, detail, false );
connect( pStatJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotStatResult(KIO::Job*)));
g_pProgressDialog->enterEventLoop( pStatJob, i18n("Getting file status: %1").tqarg(m_pFileAccess->prettyAbsPath()) );
return m_bSuccess;
}
void FileAccessJobHandler::slotStatResult(KIO::Job* pJob)
{
if ( pJob->error() )
{
//pJob->showErrorDialog(g_pProgressDialog);
m_pFileAccess->m_bExists = false;
m_bSuccess = true;
}
else
{
m_bSuccess = true;
m_pFileAccess->m_bValidData = true;
const KIO::UDSEntry e = static_cast<KIO::StatJob*>(pJob)->statResult();
m_pFileAccess->setUdsEntry( e );
}
g_pProgressDialog->exitEventLoop();
}
bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength )
{
ProgressProxy pp; // Implicitly used in slotPercent()
if ( maxLength>0 && !pp.wasCancelled() )
{
KIO::TransferJob* pJob = KIO::get( m_pFileAccess->m_url, false /*reload*/, false );
m_transferredBytes = 0;
m_pTransferBuffer = (char*)pDestBuffer;
m_maxLength = maxLength;
m_bSuccess = false;
m_pFileAccess->m_statusText = TQString();
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
connect( pJob, TQT_SIGNAL(data(KIO::Job*,const TQByteArray &)), this, TQT_SLOT(slotGetData(KIO::Job*, const TQByteArray&)));
connect( pJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(KIO::Job*, unsigned long)));
g_pProgressDialog->enterEventLoop( pJob, i18n("Reading file: %1").tqarg(m_pFileAccess->prettyAbsPath()) );
return m_bSuccess;
}
else
return true;
}
void FileAccessJobHandler::slotGetData( KIO::Job* pJob, const TQByteArray& newData )
{
if ( pJob->error() )
{
pJob->showErrorDialog(g_pProgressDialog);
}
else
{
long length = min2( long(newData.size()), m_maxLength - m_transferredBytes );
::memcpy( m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size() );
m_transferredBytes += length;
}
}
bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions )
{
if ( maxLength>0 )
{
KIO::TransferJob* pJob = KIO::put( m_pFileAccess->m_url, permissions, bOverwrite, bResume, false );
m_transferredBytes = 0;
m_pTransferBuffer = (char*)pSrcBuffer;
m_maxLength = maxLength;
m_bSuccess = false;
m_pFileAccess->m_statusText = TQString();
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotPutJobResult(KIO::Job*)));
connect( pJob, TQT_SIGNAL(dataReq(KIO::Job*, TQByteArray&)), this, TQT_SLOT(slotPutData(KIO::Job*, TQByteArray&)));
connect( pJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(KIO::Job*, unsigned long)));
g_pProgressDialog->enterEventLoop( pJob, i18n("Writing file: %1").tqarg(m_pFileAccess->prettyAbsPath()) );
return m_bSuccess;
}
else
return true;
}
void FileAccessJobHandler::slotPutData( KIO::Job* pJob, TQByteArray& data )
{
if ( pJob->error() )
{
pJob->showErrorDialog(g_pProgressDialog);
}
else
{
long maxChunkSize = 100000;
long length = min2( maxChunkSize, m_maxLength - m_transferredBytes );
bool bSuccess = data.tqresize( length );
if ( bSuccess )
{
if ( length>0 )
{
::memcpy( data.data(), m_pTransferBuffer + m_transferredBytes, data.size() );
m_transferredBytes += length;
}
}
else
{
KMessageBox::error( g_pProgressDialog, i18n("Out of memory") );
data.resize(0);
m_bSuccess = false;
}
}
}
void FileAccessJobHandler::slotPutJobResult(KIO::Job* pJob)
{
if ( pJob->error() )
{
pJob->showErrorDialog(g_pProgressDialog);
}
else
{
m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition
}
g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec()
}
bool FileAccessJobHandler::mkDir( const TQString& dirName )
{
KURL dirURL = KURL::fromPathOrURL( dirName );
if ( dirName.isEmpty() )
return false;
else if ( dirURL.isLocalFile() )
{
return TQDir().mkdir( dirURL.path() );
}
else
{
m_bSuccess = false;
KIO::SimpleJob* pJob = KIO::mkdir( dirURL );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
g_pProgressDialog->enterEventLoop( pJob, i18n("Making directory: %1").tqarg(dirName) );
return m_bSuccess;
}
}
bool FileAccessJobHandler::rmDir( const TQString& dirName )
{
KURL dirURL = KURL::fromPathOrURL( dirName );
if ( dirName.isEmpty() )
return false;
else if ( dirURL.isLocalFile() )
{
return TQDir().rmdir( dirURL.path() );
}
else
{
m_bSuccess = false;
KIO::SimpleJob* pJob = KIO::rmdir( dirURL );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
g_pProgressDialog->enterEventLoop(pJob, i18n("Removing directory: %1").tqarg(dirName));
return m_bSuccess;
}
}
bool FileAccessJobHandler::removeFile( const TQString& fileName )
{
if ( fileName.isEmpty() )
return false;
else
{
m_bSuccess = false;
KIO::SimpleJob* pJob = KIO::file_delete( KURL::fromPathOrURL(fileName), false );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
g_pProgressDialog->enterEventLoop( pJob, i18n("Removing file: %1").tqarg(fileName) );
return m_bSuccess;
}
}
bool FileAccessJobHandler::symLink( const TQString& linkTarget, const TQString& linkLocation )
{
if ( linkTarget.isEmpty() || linkLocation.isEmpty() )
return false;
else
{
m_bSuccess = false;
KIO::CopyJob* pJob = KIO::link( KURL::fromPathOrURL(linkTarget), KURL::fromPathOrURL(linkLocation), false );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
g_pProgressDialog->enterEventLoop( pJob,
i18n("Creating symbolic link: %1 -> %2").tqarg(linkLocation).tqarg(linkTarget) );
return m_bSuccess;
}
}
bool FileAccessJobHandler::rename( const TQString& dest )
{
if ( dest.isEmpty() )
return false;
KURL kurl = KURL::fromPathOrURL( dest );
if ( !kurl.isValid() )
kurl = KURL::fromPathOrURL( TQDir().absFilePath(dest) ); // assuming that invalid means relative
if ( m_pFileAccess->isLocal() && kurl.isLocalFile() )
{
return TQDir().rename( m_pFileAccess->absFilePath(), kurl.path() );
}
else
{
bool bOverwrite = false;
bool bResume = false;
bool bShowProgress = false;
int permissions=-1;
m_bSuccess = false;
KIO::FileCopyJob* pJob = KIO::file_move( m_pFileAccess->m_url, kurl, permissions, bOverwrite, bResume, bShowProgress );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
connect( pJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(KIO::Job*, unsigned long)));
g_pProgressDialog->enterEventLoop( pJob,
i18n("Renaming file: %1 -> %2").tqarg(m_pFileAccess->prettyAbsPath()).tqarg(dest) );
return m_bSuccess;
}
}
void FileAccessJobHandler::slotSimpleJobResult(KIO::Job* pJob)
{
if ( pJob->error() )
{
pJob->showErrorDialog(g_pProgressDialog);
}
else
{
m_bSuccess = true;
}
g_pProgressDialog->exitEventLoop(); // Close the dialog, return from exec()
}
// Copy local or remote files.
bool FileAccessJobHandler::copyFile( const TQString& dest )
{
ProgressProxy pp;
KURL destUrl = KURL::fromPathOrURL( dest );
m_pFileAccess->m_statusText = TQString();
if ( ! m_pFileAccess->isLocal() || ! destUrl.isLocalFile() ) // if either url is nonlocal
{
bool bOverwrite = false;
bool bResume = false;
bool bShowProgress = false;
int permissions = (m_pFileAccess->isExecutable()?0111:0)+(m_pFileAccess->isWritable()?0222:0)+(m_pFileAccess->isReadable()?0444:0);
m_bSuccess = false;
KIO::FileCopyJob* pJob = KIO::file_copy ( m_pFileAccess->m_url, destUrl, permissions, bOverwrite, bResume, bShowProgress );
connect( pJob, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotSimpleJobResult(KIO::Job*)));
connect( pJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(KIO::Job*, unsigned long)));
g_pProgressDialog->enterEventLoop( pJob,
i18n("Copying file: %1 -> %2").tqarg(m_pFileAccess->prettyAbsPath()).tqarg(dest) );
return m_bSuccess;
// Note that the KIO-slave preserves the original date, if this is supported.
}
// Both files are local:
TQString srcName = m_pFileAccess->absFilePath();
TQString destName = dest;
TQFile srcFile( srcName );
TQFile destFile( destName );
bool bReadSuccess = srcFile.open( IO_ReadOnly );
if ( bReadSuccess == false )
{
m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for reading failed. Filename: %1").tqarg(srcName);
return false;
}
bool bWriteSuccess = destFile.open( IO_WriteOnly );
if ( bWriteSuccess == false )
{
m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for writing failed. Filename: %1").tqarg(destName);
return false;
}
std::vector<char> buffer(100000);
TQ_LONG bufSize = buffer.size();
TQ_LONG srcSize = srcFile.size();
while ( srcSize > 0 && !pp.wasCancelled() )
{
TQ_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) );
if ( readSize==-1 || readSize==0 )
{
m_pFileAccess->m_statusText = i18n("Error during file copy operation: Reading failed. Filename: %1").tqarg(srcName);
return false;
}
srcSize -= readSize;
while ( readSize > 0 )
{
TQ_LONG writeSize = destFile.writeBlock( &buffer[0], readSize );
if ( writeSize==-1 || writeSize==0 )
{
m_pFileAccess->m_statusText = i18n("Error during file copy operation: Writing failed. Filename: %1").tqarg(destName);
return false;
}
readSize -= writeSize;
}
destFile.flush();
pp.setCurrent( (double)(srcFile.size()-srcSize)/srcFile.size(), false );
}
srcFile.close();
destFile.close();
// Update the times of the destFile
#ifdef _WIN32
struct _stat srcFiletqStatus;
int statResult = ::_stat( srcName.ascii(), &srcFiletqStatus );
if (statResult==0)
{
_utimbuf destTimes;
destTimes.actime = srcFiletqStatus.st_atime;/* time of last access */
destTimes.modtime = srcFiletqStatus.st_mtime;/* time of last modification */
_utime ( destName.ascii(), &destTimes );
_chmod ( destName.ascii(), srcFiletqStatus.st_mode );
}
#else
struct stat srcFiletqStatus;
int statResult = ::stat( srcName.ascii(), &srcFiletqStatus );
if (statResult==0)
{
utimbuf destTimes;
destTimes.actime = srcFiletqStatus.st_atime;/* time of last access */
destTimes.modtime = srcFiletqStatus.st_mtime;/* time of last modification */
utime ( destName.ascii(), &destTimes );
chmod ( destName.ascii(), srcFiletqStatus.st_mode );
}
#endif
return true;
}
bool wildcardMultiMatch( const TQString& wildcard, const TQString& testString, bool bCaseSensitive )
{
TQStringList sl = TQStringList::split( ";", wildcard );
for ( TQStringList::Iterator it = sl.begin(); it != sl.end(); ++it )
{
TQRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/);
if ( pattern.exactMatch( testString ) )
return true;
}
return false;
}
// class CvsIgnoreList from Cervisia cvsdir.cpp
// Copyright (C) 1999-2002 Bernd Gehrmann <bernd at mail.berlios.de>
// with elements from class StringMatcher
// Copyright (c) 2003 Andr<64>Woebeking <Woebbeking at web.de>
// Modifications for KDiff3 by Joachim Eibl
class CvsIgnoreList
{
public:
CvsIgnoreList(){}
void init(FileAccess& dir, bool bUseLocalCvsIgnore );
bool matches(const TQString& fileName, bool bCaseSensitive ) const;
private:
void addEntriesFromString(const TQString& str);
void addEntriesFromFile(const TQString& name);
void addEntry(const TQString& entry);
TQStringList m_exactPatterns;
TQStringList m_startPatterns;
TQStringList m_endPatterns;
TQStringList m_generalPatterns;
};
void CvsIgnoreList::init( FileAccess& dir, bool bUseLocalCvsIgnore )
{
static const char *ignorestr = ". .. core RCSLOG tags TAGS RCS SCCS .make.state "
".nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj "
"*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
addEntriesFromString(TQString::tqfromLatin1(ignorestr));
addEntriesFromFile(TQDir::homeDirPath() + "/.cvsignore");
addEntriesFromString(TQString::fromLocal8Bit(::getenv("CVSIGNORE")));
if (bUseLocalCvsIgnore)
{
FileAccess file(dir);
file.addPath( ".cvsignore" );
int size = file.exists() ? file.sizeForReading() : 0;
if ( size>0 )
{
char* buf=new char[size];
if (buf!=0)
{
file.readFile( buf, size );
int pos1 = 0;
for ( int pos = 0; pos<=size; ++pos )
{
if( pos==size || buf[pos]==' ' || buf[pos]=='\t' || buf[pos]=='\n' || buf[pos]=='\r' )
{
if (pos>pos1)
{
addEntry( TQString::tqfromLatin1( &buf[pos1], pos-pos1 ) );
}
++pos1;
}
}
delete buf;
}
}
}
}
void CvsIgnoreList::addEntriesFromString(const TQString& str)
{
int posLast(0);
int pos;
while ((pos = str.find(' ', posLast)) >= 0)
{
if (pos > posLast)
addEntry(str.mid(posLast, pos - posLast));
posLast = pos + 1;
}
if (posLast < static_cast<int>(str.length()))
addEntry(str.mid(posLast));
}
void CvsIgnoreList::addEntriesFromFile(const TQString &name)
{
TQFile file(name);
if( file.open(IO_ReadOnly) )
{
TQTextStream stream(&file);
while( !stream.eof() )
{
addEntriesFromString(stream.readLine());
}
}
}
void CvsIgnoreList::addEntry(const TQString& pattern)
{
if (pattern != TQString("!"))
{
if (pattern.isEmpty()) return;
// The general match is general but slow.
// Special tests for '*' and '?' at the beginning or end of a pattern
// allow fast checks.
// Count number of '*' and '?'
unsigned int nofMetaCharacters = 0;
const TQChar* pos;
pos = pattern.tqunicode();
const TQChar* posEnd;
posEnd=pos + pattern.length();
while (pos < posEnd)
{
if( *pos==TQChar('*') || *pos==TQChar('?') ) ++nofMetaCharacters;
++pos;
}
if ( nofMetaCharacters==0 )
{
m_exactPatterns.append(pattern);
}
else if ( nofMetaCharacters==1 )
{
if ( pattern.constref(0) == TQChar('*') )
{
m_endPatterns.append( pattern.right( pattern.length() - 1) );
}
else if (pattern.constref(pattern.length() - 1) == TQChar('*'))
{
m_startPatterns.append( pattern.left( pattern.length() - 1) );
}
else
{
m_generalPatterns.append(pattern.local8Bit());
}
}
else
{
m_generalPatterns.append(pattern.local8Bit());
}
}
else
{
m_exactPatterns.clear();
m_startPatterns.clear();
m_endPatterns.clear();
m_generalPatterns.clear();
}
}
bool CvsIgnoreList::matches(const TQString& text, bool bCaseSensitive ) const
{
if (m_exactPatterns.find(text) != m_exactPatterns.end())
{
return true;
}
TQStringList::ConstIterator it;
TQStringList::ConstIterator itEnd;
for ( it=m_startPatterns.begin(), itEnd=m_startPatterns.end(); it != itEnd; ++it)
{
if (text.startsWith(*it))
{
return true;
}
}
for ( it = m_endPatterns.begin(), itEnd=m_endPatterns.end(); it != itEnd; ++it)
{
if (text.mid( text.length() - (*it).length() )==*it) //(text.endsWith(*it))
{
return true;
}
}
/*
for (TQValueList<TQCString>::const_iterator it(m_generalPatterns.begin()),
itEnd(m_generalPatterns.end());
it != itEnd; ++it)
{
if (::fnmatch(*it, text.local8Bit(), FNM_PATHNAME) == 0)
{
return true;
}
}
*/
for ( it = m_generalPatterns.begin(); it != m_generalPatterns.end(); ++it )
{
TQRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/);
if ( pattern.exactMatch( text ) )
return true;
}
return false;
}
static TQString nicePath( const TQFileInfo& fi )
{
TQString fp = fi.filePath();
if ( fp.length()>2 && fp[0] == '.' && fp[1] == '/' )
{
return fp.mid(2);
}
return fp;
}
static bool cvsIgnoreExists( t_DirectoryList* pDirList )
{
t_DirectoryList::iterator i;
for( i = pDirList->begin(); i!=pDirList->end(); ++i )
{
if ( i->fileName()==".cvsignore" )
return true;
}
return false;
}
bool FileAccessJobHandler::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, const TQString& filePattern,
const TQString& fileAntiPattern, const TQString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore )
{
ProgressProxy pp;
m_pDirList = pDirList;
m_pDirList->clear();
m_bFindHidden = bFindHidden;
m_bRecursive = bRecursive;
m_bFollowDirLinks = bFollowDirLinks; // Only relevant if bRecursive==true.
m_fileAntiPattern = fileAntiPattern;
m_filePattern = filePattern;
m_dirAntiPattern = dirAntiPattern;
if ( pp.wasCancelled() )
return true; // Cancelled is not an error.
pp.setInformation( i18n("Reading directory: ") + m_pFileAccess->absFilePath(), 0, false );
if( m_pFileAccess->isLocal() )
{
TQString currentPath = TQDir::currentDirPath();
m_bSuccess = TQDir::setCurrent( m_pFileAccess->absFilePath() );
if ( m_bSuccess )
{
#ifndef _WIN32
m_bSuccess = true;
TQDir dir( "." );
dir.setSorting( TQDir::Name | TQDir::DirsFirst );
dir.setFilter( TQDir::Files | TQDir::Dirs | TQDir::Hidden );
dir.setMatchAllDirs( true );
const TQFileInfoList *fiList = dir.entryInfoList();
if ( fiList == 0 )
{
// No Permission to read directory or other error.
m_bSuccess = false;
}
else
{
TQFileInfoListIterator it( *fiList ); // create list iterator
for ( ; it.current() != 0; ++it ) // for each file...
{
TQFileInfo* fi = it.current();
if ( fi->fileName() == "." || fi->fileName()==".." )
continue;
pDirList->push_back( FileAccess( nicePath(*fi) ) );
}
}
#else
TQString pattern ="*.*";
WIN32_FIND_DATA findData;
WIN32_FIND_DATAA& findDataA=*(WIN32_FIND_DATAA*)&findData; // Needed for Win95
HANDLE searchHandle = TQT_WA_INLINE(
FindFirstFile( (TCHAR*)pattern.ucs2(), &findData ),
FindFirstFileA( pattern.local8Bit(), &findDataA )
);
if ( searchHandle != INVALID_HANDLE_VALUE )
{
TQString absPath = m_pFileAccess->absFilePath();
TQString relPath = m_pFileAccess->filePath();
bool bFirst=true;
while( ! pp.wasCancelled() )
{
if (!bFirst)
{
if ( ! TQT_WA_INLINE(
FindNextFile(searchHandle,&findData),
FindNextFileA(searchHandle,&findDataA)) )
break;
}
bFirst = false;
FileAccess fa;
fa.m_size = findData.nFileSizeLow ;//+ findData.nFileSizeHigh;
FILETIME ft;
SYSTEMTIME t;
FileTimeToLocalFileTime( &findData.ftLastWriteTime, &ft ); FileTimeToSystemTime(&ft,&t);
fa.m_modificationTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) );
FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t);
fa.m_accessTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) );
FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t);
fa.m_creationTime = TQDateTime( TQDate(t.wYear, t.wMonth, t.wDay), TQTime(t.wHour, t.wMinute, t.wSecond) );
int a = findData.dwFileAttributes;
fa.m_bWritable = ( a & FILE_ATTRIBUTE_READONLY) == 0;
fa.m_bDir = ( a & FILE_ATTRIBUTE_DIRECTORY ) != 0;
fa.m_bFile = !fa.m_bDir;
fa.m_bHidden = ( a & FILE_ATTRIBUTE_HIDDEN) != 0;
fa.m_bExecutable = false; // Useless on windows
fa.m_bExists = true;
fa.m_bReadable = true;
fa.m_bLocal = true;
fa.m_bValidData = true;
fa.m_bSymLink = false;
fa.m_fileType = 0;
fa.m_name = TQT_WA_INLINE(
TQString::fromUcs2((const ushort*)findData.cFileName),
TQString::fromLocal8Bit(findDataA.cFileName)
);
fa.m_path = fa.m_name;
fa.m_absFilePath = absPath + "/" + fa.m_name;
fa.m_url.setPath( fa.m_absFilePath );
if ( fa.m_name!="." && fa.m_name!=".." )
pDirList->push_back( fa );
}
FindClose( searchHandle );
}
else
{
TQDir::setCurrent( currentPath ); // restore current path
return false;
}
#endif
}
TQDir::setCurrent( currentPath ); // restore current path
}
else
{
bool bShowProgress = false;
KIO::ListJob* pListJob=0;
pListJob = KIO::listDir( m_pFileAccess->m_url, bShowProgress, true /*bFindHidden*/ );
m_bSuccess = false;
if ( pListJob!=0 )
{
connect( pListJob, TQT_SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList& ) ),
this, TQT_SLOT( slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& )) );
connect( pListJob, TQT_SIGNAL( result( KIO::Job* )),
this, TQT_SLOT( slotSimpleJobResult(KIO::Job*) ) );
connect( pListJob, TQT_SIGNAL( infoMessage(KIO::Job*, const TQString&)),
this, TQT_SLOT( slotListDirInfoMessage(KIO::Job*, const TQString&) ));
// This line makes the transfer via fish unreliable.:-(
//connect( pListJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)), this, TQT_SLOT(slotPercent(KIO::Job*, unsigned long)));
g_pProgressDialog->enterEventLoop( pListJob,
i18n("Listing directory: %1").tqarg(m_pFileAccess->prettyAbsPath()) );
}
}
CvsIgnoreList cvsIgnoreList;
if ( bUseCvsIgnore )
{
cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) );
}
#ifdef _WIN32
bool bCaseSensitive = false;
#else
bool bCaseSensitive = true;
#endif
// Now remove all entries that don't match:
t_DirectoryList::iterator i;
for( i = pDirList->begin(); i!=pDirList->end(); )
{
t_DirectoryList::iterator i2=i;
++i2;
TQString fn = i->fileName();
if ( (!bFindHidden && i->isHidden() )
||
(i->isFile() &&
( !wildcardMultiMatch( filePattern, i->fileName(), bCaseSensitive ) ||
wildcardMultiMatch( fileAntiPattern, i->fileName(), bCaseSensitive ) ) )
||
(i->isDir() && wildcardMultiMatch( dirAntiPattern, i->fileName(), bCaseSensitive ) )
||
cvsIgnoreList.matches( i->fileName(), bCaseSensitive )
)
{
// Remove it
pDirList->erase( i );
i = i2;
}
else
{
++i;
}
}
if ( bRecursive )
{
t_DirectoryList subDirsList;
t_DirectoryList::iterator i;
for( i = m_pDirList->begin(); i!=m_pDirList->end(); ++i )
{
if ( i->isDir() && (!i->isSymLink() || m_bFollowDirLinks))
{
t_DirectoryList dirList;
i->listDir( &dirList, bRecursive, bFindHidden,
filePattern, fileAntiPattern, dirAntiPattern, bFollowDirLinks, bUseCvsIgnore );
t_DirectoryList::iterator j;
for( j = dirList.begin(); j!=dirList.end(); ++j )
{
j->m_path = i->fileName() + "/" + j->m_path;
}
// append data onto the main list
subDirsList.splice( subDirsList.end(), dirList );
}
}
m_pDirList->splice( m_pDirList->end(), subDirsList );
}
return m_bSuccess;
}
void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l )
{
KURL parentUrl( m_pFileAccess->m_absFilePath );
KIO::UDSEntryList::ConstIterator i;
for ( i=l.begin(); i!=l.end(); ++i )
{
const KIO::UDSEntry& e = *i;
FileAccess fa;
fa.setUdsEntry( e );
if ( fa.filePath() != "." && fa.filePath() != ".." )
{
fa.m_url = parentUrl;
fa.m_url.addPath( fa.filePath() );
fa.m_absFilePath = fa.m_url.url();
m_pDirList->push_back( fa );
}
}
}
void FileAccessJobHandler::slotListDirInfoMessage( KIO::Job*, const TQString& msg )
{
g_pProgressDialog->setInformation( msg, 0.0 );
}
void FileAccessJobHandler::slotPercent( KIO::Job*, unsigned long percent )
{
g_pProgressDialog->setCurrent( percent/100.0 );
}
ProgressDialog::ProgressDialog( TQWidget* pParent )
: TQDialog( pParent, 0, true )
{
m_bStayHidden = false;
TQVBoxLayout* tqlayout = new TQVBoxLayout(this);
m_pInformation = new TQLabel( " ", this );
tqlayout->addWidget( m_pInformation );
m_pProgressBar = new KProgress(1000, this);
tqlayout->addWidget( m_pProgressBar );
m_pSubInformation = new TQLabel( " ", this);
tqlayout->addWidget( m_pSubInformation );
m_pSubProgressBar = new KProgress(1000, this);
tqlayout->addWidget( m_pSubProgressBar );
m_pSlowJobInfo = new TQLabel( " ", this);
tqlayout->addWidget( m_pSlowJobInfo );
TQHBoxLayout* htqlayout = new TQHBoxLayout( tqlayout );
htqlayout->addStretch(1);
m_pAbortButton = new TQPushButton( i18n("&Cancel"), this);
htqlayout->addWidget( m_pAbortButton );
connect( m_pAbortButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotAbort()) );
m_progressDelayTimer = 0;
resize( 400, 100 );
m_t1.start();
m_t2.start();
m_bWasCancelled = false;
m_pJob = 0;
}
void ProgressDialog::setStayHidden( bool bStayHidden )
{
m_bStayHidden = bStayHidden;
}
void ProgressDialog::push()
{
ProgressLevelData pld;
if ( !m_progressStack.empty() )
{
pld.m_dRangeMax = m_progressStack.back().m_dSubRangeMax;
pld.m_dRangeMin = m_progressStack.back().m_dSubRangeMin;
}
else
{
m_bWasCancelled = false;
m_t1.restart();
m_t2.restart();
if ( !m_bStayHidden )
show();
}
m_progressStack.push_back( pld );
}
void ProgressDialog::pop( bool bRedrawUpdate )
{
if ( !m_progressStack.empty() )
{
m_progressStack.pop_back();
if ( m_progressStack.empty() )
hide();
else
recalc(bRedrawUpdate);
}
}
void ProgressDialog::setInformation(const TQString& info, double dCurrent, bool bRedrawUpdate )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_dCurrent = dCurrent;
int level = m_progressStack.size();
if ( level==1 )
{
m_pInformation->setText( info );
m_pSubInformation->setText("");
}
else if ( level==2 )
{
m_pSubInformation->setText( info );
}
recalc(bRedrawUpdate);
}
void ProgressDialog::setInformation(const TQString& info, bool bRedrawUpdate )
{
if ( m_progressStack.empty() )
return;
//ProgressLevelData& pld = m_progressStack.back();
int level = m_progressStack.size();
if ( level==1 )
{
m_pInformation->setText( info );
m_pSubInformation->setText( "" );
}
else if ( level==2 )
{
m_pSubInformation->setText( info );
}
recalc(bRedrawUpdate);
}
void ProgressDialog::setMaxNofSteps( int maxNofSteps )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_maxNofSteps = maxNofSteps;
pld.m_dCurrent = 0;
}
void ProgressDialog::step( bool bRedrawUpdate )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_dCurrent += 1.0/pld.m_maxNofSteps;
recalc(bRedrawUpdate);
}
void ProgressDialog::setCurrent( double dSubCurrent, bool bRedrawUpdate )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_dCurrent = dSubCurrent;
recalc( bRedrawUpdate );
}
// The progressbar goes from 0 to 1 usually.
// By supplying a subrange transformation the subCurrent-values
// 0 to 1 will be transformed to dMin to dMax instead.
// Requirement: 0 < dMin < dMax < 1
void ProgressDialog::setRangeTransformation( double dMin, double dMax )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_dRangeMin = dMin;
pld.m_dRangeMax = dMax;
pld.m_dCurrent = 0;
}
void ProgressDialog::setSubRangeTransformation( double dMin, double dMax )
{
if ( m_progressStack.empty() )
return;
ProgressLevelData& pld = m_progressStack.back();
pld.m_dSubRangeMin = dMin;
pld.m_dSubRangeMax = dMax;
}
void qt_enter_modal(TQWidget*);
void qt_leave_modal(TQWidget*);
void ProgressDialog::enterEventLoop( KIO::Job* pJob, const TQString& jobInfo )
{
m_pJob = pJob;
m_pSlowJobInfo->setText("");
m_currentJobInfo = jobInfo;
killTimer( m_progressDelayTimer );
m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */
// instead of using exec() the eventloop is entered and exited often without hiding/showing the window.
qt_enter_modal(this);
tqApp->eventLoop()->enterLoop();
qt_leave_modal(this);
}
void ProgressDialog::exitEventLoop()
{
killTimer( m_progressDelayTimer );
m_progressDelayTimer = 0;
m_pJob = 0;
tqApp->eventLoop()->exitLoop();
}
void ProgressDialog::recalc( bool bUpdate )
{
killTimer( m_progressDelayTimer );
m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */
int level = m_progressStack.size();
if( ( bUpdate && level==1) || m_t1.elapsed()>200 )
{
if (m_progressStack.empty() )
{
m_pProgressBar->setProgress( 0 );
m_pSubProgressBar->setProgress( 0 );
}
else
{
std::list<ProgressLevelData>::iterator i = m_progressStack.begin();
m_pProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) );
++i;
if ( i!=m_progressStack.end() )
m_pSubProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) );
else
m_pSubProgressBar->setProgress( int( 1000.0 * m_progressStack.front().m_dSubRangeMin ) );
}
if ( !m_bStayHidden && !isVisible() )
show();
tqApp->processEvents();
m_t1.restart();
}
}
#include <tqtimer.h>
void ProgressDialog::show()
{
killTimer( m_progressDelayTimer );
m_progressDelayTimer = 0;
if ( !isVisible() && (parentWidget()==0 || parentWidget()->isVisible()) )
{
TQDialog::show();
}
}
void ProgressDialog::hide()
{
killTimer( m_progressDelayTimer );
m_progressDelayTimer = 0;
// Calling TQDialog::hide() directly doesn't always work. (?)
TQTimer::singleShot( 100, this, TQT_SLOT(delayedHide()) );
}
void ProgressDialog::delayedHide()
{
if (m_pJob!=0)
{
m_pJob->kill(false);
m_pJob = 0;
}
TQDialog::hide();
m_pInformation->setText( "" );
//m_progressStack.clear();
m_pProgressBar->setProgress( 0 );
m_pSubProgressBar->setProgress( 0 );
m_pSubInformation->setText("");
m_pSlowJobInfo->setText("");
}
void ProgressDialog::reject()
{
m_bWasCancelled = true;
TQDialog::reject();
}
void ProgressDialog::slotAbort()
{
reject();
}
bool ProgressDialog::wasCancelled()
{
if( m_t2.elapsed()>100 )
{
tqApp->processEvents();
m_t2.restart();
}
return m_bWasCancelled;
}
void ProgressDialog::timerEvent(TQTimerEvent*)
{
if( !isVisible() )
{
show();
}
m_pSlowJobInfo->setText( m_currentJobInfo );
}
ProgressProxy::ProgressProxy()
{
g_pProgressDialog->push();
}
ProgressProxy::~ProgressProxy()
{
g_pProgressDialog->pop(false);
}
void ProgressProxy::setInformation( const TQString& info, bool bRedrawUpdate )
{
g_pProgressDialog->setInformation( info, bRedrawUpdate );
}
void ProgressProxy::setInformation( const TQString& info, double dCurrent, bool bRedrawUpdate )
{
g_pProgressDialog->setInformation( info, dCurrent, bRedrawUpdate );
}
void ProgressProxy::setCurrent( double dCurrent, bool bRedrawUpdate )
{
g_pProgressDialog->setCurrent( dCurrent, bRedrawUpdate );
}
void ProgressProxy::step( bool bRedrawUpdate )
{
g_pProgressDialog->step( bRedrawUpdate );
}
void ProgressProxy::setMaxNofSteps( int maxNofSteps )
{
g_pProgressDialog->setMaxNofSteps( maxNofSteps );
}
bool ProgressProxy::wasCancelled()
{
return g_pProgressDialog->wasCancelled();
}
void ProgressProxy::setRangeTransformation( double dMin, double dMax )
{
g_pProgressDialog->setRangeTransformation( dMin, dMax );
}
void ProgressProxy::setSubRangeTransformation( double dMin, double dMax )
{
g_pProgressDialog->setSubRangeTransformation( dMin, dMax );
}
#include "fileaccess.moc"