file.cpp
branchrelease-1-12-maintained
changeset 81 876eed30ba3b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/file.cpp	Tue Mar 23 11:54:30 2010 +0000
     1.3 @@ -0,0 +1,500 @@
     1.4 +#include <QDir>
     1.5 +#include <QMessageBox>
     1.6 +#include <QPixmap>
     1.7 +#include <QLabel>
     1.8 +#include <QTextStream>
     1.9 +#include <iostream>
    1.10 +#include <cstdlib>
    1.11 +
    1.12 +#include "file.h"
    1.13 +#include "process.h"
    1.14 +
    1.15 +#if defined(Q_OS_WIN32)
    1.16 +#include "mkdtemp.h"
    1.17 +#include <windows.h>
    1.18 +#endif
    1.19 +
    1.20 +QString maskPath(QString p)
    1.21 +{
    1.22 +	// Change " " to "\ " to enable blanks in filenames
    1.23 +	p=p.replace(QChar('&'),"\\&");
    1.24 +	return p.replace(QChar(' '),"\\ ");
    1.25 +}
    1.26 +
    1.27 +QString convertToRel (const QString &src, const QString &dst)
    1.28 +{
    1.29 +	QString s=src;
    1.30 +	QString d=dst;
    1.31 +	int i;
    1.32 +
    1.33 +	if (s==d) 
    1.34 +	{
    1.35 +		// Special case, we just need the name of the file,
    1.36 +		// not the complete path
    1.37 +		i=d.findRev ("/");
    1.38 +		d=d.right (d.length()-i-1);
    1.39 +	} else
    1.40 +	{
    1.41 +		// Find relative path from src to dst
    1.42 +
    1.43 +		// Remove the first "/"
    1.44 +		if (s.section ("/",0,0).isEmpty()) 
    1.45 +		{
    1.46 +			s=s.right (s.length()-1);
    1.47 +			d=d.right (d.length()-1);
    1.48 +		}
    1.49 +		
    1.50 +		// remove identical left parts
    1.51 +		while (s.section("/",0,0) == d.section("/",0,0) ) 
    1.52 +		{
    1.53 +			i=s.find ("/");
    1.54 +			s=s.right (s.length()-i-1);
    1.55 +			d=d.right (d.length()-i-1);
    1.56 +		}
    1.57 +
    1.58 +		// Now take care of paths where we have to go back first
    1.59 +		int srcsep=s.count("/");
    1.60 +		int dstsep=d.count("/");
    1.61 +		if (srcsep <=  dstsep )
    1.62 +		{
    1.63 +			// find path to go up first and then back to dst
    1.64 +			i=1;
    1.65 +			while (i<=srcsep) 
    1.66 +			{
    1.67 +				d="../"+d;
    1.68 +				i++;
    1.69 +			}	
    1.70 +		}
    1.71 +	}	
    1.72 +	return d;
    1.73 +}
    1.74 +
    1.75 +#include <QFileDialog>
    1.76 +extern QString vymName;
    1.77 +extern QDir lastFileDir;
    1.78 +
    1.79 +QString browseDirectory (QWidget *parent,const QString &caption)
    1.80 +{
    1.81 +	QFileDialog fd(parent,caption);
    1.82 +	fd.setMode (QFileDialog::DirectoryOnly);
    1.83 +	fd.setCaption(vymName+ " - "+caption);
    1.84 +	fd.setDir (lastFileDir);
    1.85 +	fd.show();
    1.86 +	
    1.87 +	if ( fd.exec() == QDialog::Accepted )
    1.88 +		return fd.selectedFile();
    1.89 +	else
    1.90 +		return "";
    1.91 +}
    1.92 +
    1.93 +
    1.94 +
    1.95 +bool reallyWriteDirectory(const QString &dir)
    1.96 +{
    1.97 +	QStringList eList = QDir(dir).entryList();
    1.98 +	if (eList.first() ==".")  eList.pop_front();	// remove "."
    1.99 +	if (eList.first() =="..") eList.pop_front();	// remove "."
   1.100 +	if (!eList.isEmpty())
   1.101 +	{
   1.102 +		QMessageBox mb( vymName,
   1.103 +			QObject::tr("The directory %1 is not empty.\nDo you risk to overwrite its contents?","write directory").arg(dir),
   1.104 +		QMessageBox::Warning,
   1.105 +		QMessageBox::Yes ,
   1.106 +		QMessageBox::Cancel | QMessageBox::Default,
   1.107 +		QMessageBox::NoButton );
   1.108 +
   1.109 +		mb.setButtonText( QMessageBox::Yes, QObject::tr("Overwrite") );
   1.110 +		mb.setButtonText( QMessageBox::No, QObject::tr("Cancel"));
   1.111 +		switch( mb.exec() ) 
   1.112 +		{
   1.113 +			case QMessageBox::Yes:
   1.114 +				// save 
   1.115 +				return true;
   1.116 +			case QMessageBox::Cancel:
   1.117 +				// do nothing
   1.118 +				return false;
   1.119 +		}
   1.120 +	}
   1.121 +	return true;
   1.122 +}
   1.123 +
   1.124 +QString makeTmpDir (bool &ok, QString prefix)
   1.125 +{
   1.126 +	bool b;
   1.127 +	QString path=makeUniqueDir (b,QDir::tempPath()+"/"+prefix+"-XXXXXX");
   1.128 +	ok=b;
   1.129 +	return path;
   1.130 +}
   1.131 +
   1.132 +bool isInTmpDir(QString fn)
   1.133 +{
   1.134 +	QString temp=QDir::tempPath();
   1.135 +	int l=temp.length();
   1.136 +	return fn.left(l)==temp;
   1.137 +}
   1.138 +
   1.139 +QString makeUniqueDir (bool &ok,QString s)
   1.140 +{
   1.141 +	// Create unique directory e.g. for s="/tmp/vym-XXXXXX"
   1.142 +
   1.143 +	// Convert Separators
   1.144 +	s=QDir::convertSeparators(s);
   1.145 +
   1.146 +	// Convert QString to string 
   1.147 +	ok=true;
   1.148 +	char *p;
   1.149 +	int bytes=s.length();
   1.150 +	p=(char*) malloc (bytes+1);
   1.151 +	int i;
   1.152 +	for (i=0;i<bytes;i++)
   1.153 +		p[i]=s.at(i).latin1();
   1.154 +	p[bytes]=0;	
   1.155 +
   1.156 +	QString r=mkdtemp (p);
   1.157 +	if (r.isEmpty()) ok=false;
   1.158 +	free (p);
   1.159 +	return r;
   1.160 +}
   1.161 +
   1.162 +void removeDir(QDir d)
   1.163 +{
   1.164 +	// This check should_ not be necessary, but proved to be useful ;-)
   1.165 +	if (!isInTmpDir(d.path()))
   1.166 +	{
   1.167 +		qWarning ("file.cpp::removeDir should remove "+d.path()+" - aborted.");
   1.168 +		return;
   1.169 +	}
   1.170 +
   1.171 +	// Traverse directories
   1.172 +	d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
   1.173 +	QFileInfoList list = d.entryInfoList();
   1.174 +	QFileInfo fi;
   1.175 +
   1.176 +	for (int i = 0; i < list.size(); ++i) 
   1.177 +	{
   1.178 +		fi=list.at(i);
   1.179 +		if (fi.fileName() != "." && fi.fileName() != ".." )
   1.180 +		{
   1.181 +			if ( !d.cd(fi.fileName()) ) 
   1.182 +				qWarning ("removeDir() cannot find the directory "+fi.fileName());
   1.183 +			else 
   1.184 +			{
   1.185 +				// Recursively remove subdirs
   1.186 +				removeDir (d);
   1.187 +				d.cdUp();
   1.188 +			}
   1.189 +		}	
   1.190 +	}
   1.191 +
   1.192 +	// Traverse files
   1.193 +	d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
   1.194 +	list = d.entryInfoList();
   1.195 +
   1.196 +	for (int i = 0; i < list.size(); ++i) 
   1.197 +	{
   1.198 +		fi=list.at(i);
   1.199 +		QFile (fi.filePath()).remove(); 
   1.200 +	}	
   1.201 +
   1.202 +	if (!d.rmdir(d.path()))
   1.203 +		qWarning ("removeDir("+d.path()+") failed!");
   1.204 +}		
   1.205 +
   1.206 +void copyDir (QDir src, QDir dst)
   1.207 +{
   1.208 +	system ("cp -r "+src.path()+"/* "+dst.path());
   1.209 +
   1.210 +	/*
   1.211 +	ErrorCode err=success;
   1.212 +
   1.213 +	Process *cpProc=new Process ();
   1.214 +	QStringList args;
   1.215 +	cpProc->setWorkingDirectory (src.path());
   1.216 +	args <<"-r";
   1.217 +	args <<src.path();
   1.218 +	args <<dst.path();
   1.219 +
   1.220 +	cpProc->start ("cp",args);
   1.221 +	if (!cpProc->waitForStarted() )
   1.222 +	{	
   1.223 +		// zip could not be started
   1.224 +		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.225 +					   QObject::tr("Couldn't start zip to compress data."));
   1.226 +		err=aborted;
   1.227 +	} else
   1.228 +	{
   1.229 +		// zip could be started
   1.230 +		cpProc->waitForFinished();
   1.231 +		if (cpProc->exitStatus()!=QProcess::NormalExit )
   1.232 +		{
   1.233 +			QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.234 +						   QObject::tr("cp didn't exit normally")+
   1.235 +						   "\n" + cpProc->getErrout());
   1.236 +			err=aborted;
   1.237 +		} else
   1.238 +		{
   1.239 +			if (cpProc->exitCode()>0)
   1.240 +			{
   1.241 +				QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.242 +						   QString("cp exit code:  %1").arg(cpProc->exitCode() )+
   1.243 +						   "\n" + cpProc->getErrout() );
   1.244 +				err=aborted;
   1.245 +			}
   1.246 +		}
   1.247 +	}	// cp could be started
   1.248 +	*/
   1.249 +}
   1.250 +
   1.251 +void makeSubDirs (const QString &s)
   1.252 +{
   1.253 +	QDir d(s);
   1.254 +	d.mkdir(s);
   1.255 +	d.mkdir ("images");	
   1.256 +	d.mkdir ("flags");	
   1.257 +}
   1.258 +
   1.259 +ErrorCode zipDir (const QDir &zipDir, const QString &zipName)
   1.260 +{
   1.261 +	ErrorCode err=success;
   1.262 +	
   1.263 +	// zip the temporary directory
   1.264 +	QStringList args;
   1.265 +	Process *zipProc=new Process ();
   1.266 +	zipProc->setWorkingDirectory (zipDir.path());
   1.267 +	args <<"-r";
   1.268 +	args <<zipName;
   1.269 +	args <<".";
   1.270 +
   1.271 +	zipProc->start ("zip",args);
   1.272 +	if (!zipProc->waitForStarted() )
   1.273 +	{	
   1.274 +		// zip could not be started
   1.275 +		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.276 +					   QObject::tr("Couldn't start zip to compress data."));
   1.277 +		err=aborted;
   1.278 +	} else
   1.279 +	{
   1.280 +		// zip could be started
   1.281 +		zipProc->waitForFinished();
   1.282 +		if (zipProc->exitStatus()!=QProcess::NormalExit )
   1.283 +		{
   1.284 +			QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.285 +						   QObject::tr("zip didn't exit normally")+
   1.286 +						   "\n" + zipProc->getErrout());
   1.287 +			err=aborted;
   1.288 +		} else
   1.289 +		{
   1.290 +			if (zipProc->exitCode()>0)
   1.291 +			{
   1.292 +				QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.293 +						   QString("zip exit code:  %1").arg(zipProc->exitCode() )+
   1.294 +						   "\n" + zipProc->getErrout() );
   1.295 +				err=aborted;
   1.296 +			}
   1.297 +		}
   1.298 +	}	// zip could be started
   1.299 +	return err;	
   1.300 +}
   1.301 +
   1.302 +ErrorCode unzipDir (const QDir &zipDir, const QString &zipName)
   1.303 +{
   1.304 +	ErrorCode err=success;
   1.305 +
   1.306 +	// Try to unzip file
   1.307 +#if !defined(Q_OS_WIN32)
   1.308 +	QStringList args;
   1.309 +	Process *zipProc=new Process ();
   1.310 +	zipProc->setWorkingDirectory (zipDir.path());
   1.311 +	args << "-o";	// overwrite existing files!
   1.312 +	args << zipName ;
   1.313 +	args << "-d";
   1.314 +	args << zipDir.path();
   1.315 +
   1.316 +	zipProc->start ("unzip",args);
   1.317 +	if (!zipProc->waitForStarted() )
   1.318 +	{
   1.319 +		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.320 +					   QObject::tr("Couldn't start unzip to decompress data."));
   1.321 +		err=aborted;
   1.322 +		
   1.323 +	} else
   1.324 +	{
   1.325 +		zipProc->waitForFinished();
   1.326 +		if (zipProc->exitStatus()!=QProcess::NormalExit )
   1.327 +		{
   1.328 +			QMessageBox::critical( 0,QObject::tr( "Critical Error" ),
   1.329 +						   QObject::tr("unzip didn't exit normally") +
   1.330 +						   zipProc->getErrout() );
   1.331 +			err=aborted;
   1.332 +		} else
   1.333 +		{
   1.334 +			if (zipProc->exitCode()>0)
   1.335 +			{
   1.336 +				if (zipProc->exitCode()==9)
   1.337 +					// no zipped file, but maybe .xml or old version? Try again.
   1.338 +					err=nozip;
   1.339 +				else	
   1.340 +				{
   1.341 +					QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   1.342 +								   QString("unzip exit code:  %1").arg(zipProc->exitCode() ) +
   1.343 +								   zipProc->getErrout() );
   1.344 +					err=aborted;
   1.345 +				}
   1.346 +			} 
   1.347 +		}
   1.348 +	}
   1.349 +#else
   1.350 +    // Do this process creation using Win32 API.
   1.351 +    //! Create process.
   1.352 +    PROCESS_INFORMATION piProcInfo;
   1.353 +    STARTUPINFO siStartInfo;
   1.354 +
   1.355 +    // Initialize members of the PROCESS_INFORMATION structure.
   1.356 +    ::ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
   1.357 +
   1.358 +    // Set up members of the STARTUPINFO structure.
   1.359 +    ::ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   1.360 +    siStartInfo.cb = sizeof(STARTUPINFO);
   1.361 +
   1.362 +    // Create command line.
   1.363 +    QString argv("unzip -o ");
   1.364 +    argv.append(QDir::convertSeparators(zipName));
   1.365 +    argv.append(" -d ");
   1.366 +    argv.append(QDir::convertSeparators(zipDir.path()));
   1.367 +
   1.368 +    // Create the child process.
   1.369 +    if( !::CreateProcess(NULL, 
   1.370 +        (LPWSTR)argv.unicode(), // command line
   1.371 +        NULL, // process security attributes
   1.372 +        NULL, // primary thread security attributes
   1.373 +        TRUE, // handles are inherited
   1.374 +        0, // creation flags
   1.375 +        NULL, // use parent's environment
   1.376 +        NULL, // use parent's current directory
   1.377 +        &siStartInfo, // STARTUPINFO pointer
   1.378 +        &piProcInfo) ) // receives PROCESS_INFORMATION
   1.379 +    {
   1.380 +        err = aborted;
   1.381 +    }
   1.382 +    else
   1.383 +    {
   1.384 +        // Wait for it to finish.
   1.385 +        ::WaitForSingleObject( piProcInfo.hProcess, 10000 );
   1.386 +    }
   1.387 +#endif
   1.388 +	return err;	
   1.389 +}
   1.390 +
   1.391 +bool loadStringFromDisk (const QString &fname, QString &s)
   1.392 +{
   1.393 +	s="";
   1.394 +	QFile file ( fname);
   1.395 +	if ( !file.open( QIODevice::ReadOnly ) ) return false;
   1.396 +
   1.397 +	QTextStream ts( &file );
   1.398 +	ts.setEncoding (QTextStream::UnicodeUTF8);
   1.399 +	while ( !ts.atEnd() ) 
   1.400 +		s+=ts.readLine()+"\n"; 
   1.401 +	file.close();
   1.402 +	return true;
   1.403 +}
   1.404 +
   1.405 +bool saveStringToDisk (const QString &fname, const QString &s)
   1.406 +{
   1.407 +	QFile file( fname);
   1.408 +
   1.409 +	file.setName ( fname);
   1.410 +	if ( !file.open( QIODevice::WriteOnly ) ) 
   1.411 +	{
   1.412 +		file.close();
   1.413 +		return false;
   1.414 +	}	
   1.415 +
   1.416 +	// Write it finally, and write in UTF8, no matter what 
   1.417 +	QTextStream ts( &file );
   1.418 +	ts.setEncoding (QTextStream::UnicodeUTF8);
   1.419 +	ts << s;
   1.420 +	file.close();
   1.421 +	return true;
   1.422 +}
   1.423 +
   1.424 +
   1.425 +ImagePreview::ImagePreview (QWidget *par=0): QLabel (par)
   1.426 +{
   1.427 +	fdia=(Q3FileDialog*)par;
   1.428 +}
   1.429 +
   1.430 +void ImagePreview::previewUrl( const Q3Url &u )
   1.431 +{
   1.432 +    QString path = u.path();
   1.433 +    QPixmap pix( path );
   1.434 +    if ( pix.isNull() )
   1.435 +	{
   1.436 +		// Strange: If we have fd->setMode (QFileDialog::ExistingFiles)
   1.437 +		// in the filedialog, then there are 3 calls to previewURL 
   1.438 +		// for each selection. And only the first is the actual selected file
   1.439 +		// while the following 2 point to the directory above the current one.
   1.440 +		// So here's my workaround:
   1.441 +		
   1.442 +		if (fdia && fdia->selectedFiles().count()==0)
   1.443 +			setText( QObject::tr("This is not an image.") );
   1.444 +		if (fdia &&fdia->selectedFiles().count()>1)
   1.445 +			setText( QObject::tr("Sorry, no preview for\nmultiple selected files.") );
   1.446 +	}	
   1.447 +    else
   1.448 +	{
   1.449 +		float max_w=300;
   1.450 +		float max_h=300;
   1.451 +		float r;
   1.452 +		if (pix.width()>max_w)
   1.453 +		{
   1.454 +			r=max_w / pix.width();
   1.455 +			pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
   1.456 +			// TODO not a resize, but a shrink/enlarge is needed here...
   1.457 +		}
   1.458 +		if (pix.height()>max_h)
   1.459 +		{
   1.460 +			r=max_h / pix.height();
   1.461 +			pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
   1.462 +			// TODO not a resize, but a shrink/enlarge is needed here...
   1.463 +		}
   1.464 +        setPixmap( pix );
   1.465 +	}	
   1.466 +}
   1.467 +
   1.468 +ImageIO::ImageIO ()
   1.469 +{
   1.470 +	// Create list with supported image types
   1.471 +	// foreach (QByteArray format, QImageWriter::supportedImageFormats()) 
   1.472 +	// imageTypes.append( tr("%1...").arg(QString(format).toUpper()));
   1.473 +	imageFilters.append ("Images (*.png *.jpg *.jpeg *.bmp *.bmp *.ppm *.xpm *.xbm)");
   1.474 +	imageTypes.append ("PNG");
   1.475 +	imageFilters.append ("Portable Network Graphics (*.png)");
   1.476 +	imageTypes.append ("PNG");
   1.477 +	imageFilters.append ("Joint Photographic Experts Group (*.jpg)");
   1.478 +	imageTypes.append ("JPG");
   1.479 +	imageFilters.append ("Joint Photographic Experts Group (*.jpeg)");
   1.480 +	imageTypes.append ("JPG");
   1.481 +	imageFilters.append ("Windows Bitmap (*.bmp)");
   1.482 +	imageTypes.append ("BMP");
   1.483 +	imageFilters.append ("Portable Pixmap (*.ppm)");
   1.484 +	imageTypes.append ("PPM");
   1.485 +	imageFilters.append ("X11 Bitmap (*.xpm)");
   1.486 +	imageTypes.append ("XPM");
   1.487 +	imageFilters.append ("X11 Bitmap (*.xbm)");
   1.488 +	imageTypes.append ("XBM");
   1.489 +}
   1.490 +
   1.491 +QStringList ImageIO::getFilters()
   1.492 +{
   1.493 +	return imageFilters;
   1.494 +}
   1.495 +
   1.496 +QString ImageIO::getType(QString filter)
   1.497 +{
   1.498 +	for (int i=0;i<imageFilters.count()+1;i++)
   1.499 +		if (imageFilters.at(i)==filter) return imageTypes.at(i);
   1.500 +	return QString();	
   1.501 +}
   1.502 +
   1.503 +