file.cpp
author insilmaril
Tue, 23 Mar 2010 11:54:30 +0000
branchrelease-1-12-maintained
changeset 81 876eed30ba3b
permissions -rw-r--r--
Patch from Xavier Oswald to compile with older compilers
     1 #include <QDir>
     2 #include <QMessageBox>
     3 #include <QPixmap>
     4 #include <QLabel>
     5 #include <QTextStream>
     6 #include <iostream>
     7 #include <cstdlib>
     8 
     9 #include "file.h"
    10 #include "process.h"
    11 
    12 #if defined(Q_OS_WIN32)
    13 #include "mkdtemp.h"
    14 #include <windows.h>
    15 #endif
    16 
    17 QString maskPath(QString p)
    18 {
    19 	// Change " " to "\ " to enable blanks in filenames
    20 	p=p.replace(QChar('&'),"\\&");
    21 	return p.replace(QChar(' '),"\\ ");
    22 }
    23 
    24 QString convertToRel (const QString &src, const QString &dst)
    25 {
    26 	QString s=src;
    27 	QString d=dst;
    28 	int i;
    29 
    30 	if (s==d) 
    31 	{
    32 		// Special case, we just need the name of the file,
    33 		// not the complete path
    34 		i=d.findRev ("/");
    35 		d=d.right (d.length()-i-1);
    36 	} else
    37 	{
    38 		// Find relative path from src to dst
    39 
    40 		// Remove the first "/"
    41 		if (s.section ("/",0,0).isEmpty()) 
    42 		{
    43 			s=s.right (s.length()-1);
    44 			d=d.right (d.length()-1);
    45 		}
    46 		
    47 		// remove identical left parts
    48 		while (s.section("/",0,0) == d.section("/",0,0) ) 
    49 		{
    50 			i=s.find ("/");
    51 			s=s.right (s.length()-i-1);
    52 			d=d.right (d.length()-i-1);
    53 		}
    54 
    55 		// Now take care of paths where we have to go back first
    56 		int srcsep=s.count("/");
    57 		int dstsep=d.count("/");
    58 		if (srcsep <=  dstsep )
    59 		{
    60 			// find path to go up first and then back to dst
    61 			i=1;
    62 			while (i<=srcsep) 
    63 			{
    64 				d="../"+d;
    65 				i++;
    66 			}	
    67 		}
    68 	}	
    69 	return d;
    70 }
    71 
    72 #include <QFileDialog>
    73 extern QString vymName;
    74 extern QDir lastFileDir;
    75 
    76 QString browseDirectory (QWidget *parent,const QString &caption)
    77 {
    78 	QFileDialog fd(parent,caption);
    79 	fd.setMode (QFileDialog::DirectoryOnly);
    80 	fd.setCaption(vymName+ " - "+caption);
    81 	fd.setDir (lastFileDir);
    82 	fd.show();
    83 	
    84 	if ( fd.exec() == QDialog::Accepted )
    85 		return fd.selectedFile();
    86 	else
    87 		return "";
    88 }
    89 
    90 
    91 
    92 bool reallyWriteDirectory(const QString &dir)
    93 {
    94 	QStringList eList = QDir(dir).entryList();
    95 	if (eList.first() ==".")  eList.pop_front();	// remove "."
    96 	if (eList.first() =="..") eList.pop_front();	// remove "."
    97 	if (!eList.isEmpty())
    98 	{
    99 		QMessageBox mb( vymName,
   100 			QObject::tr("The directory %1 is not empty.\nDo you risk to overwrite its contents?","write directory").arg(dir),
   101 		QMessageBox::Warning,
   102 		QMessageBox::Yes ,
   103 		QMessageBox::Cancel | QMessageBox::Default,
   104 		QMessageBox::NoButton );
   105 
   106 		mb.setButtonText( QMessageBox::Yes, QObject::tr("Overwrite") );
   107 		mb.setButtonText( QMessageBox::No, QObject::tr("Cancel"));
   108 		switch( mb.exec() ) 
   109 		{
   110 			case QMessageBox::Yes:
   111 				// save 
   112 				return true;
   113 			case QMessageBox::Cancel:
   114 				// do nothing
   115 				return false;
   116 		}
   117 	}
   118 	return true;
   119 }
   120 
   121 QString makeTmpDir (bool &ok, QString prefix)
   122 {
   123 	bool b;
   124 	QString path=makeUniqueDir (b,QDir::tempPath()+"/"+prefix+"-XXXXXX");
   125 	ok=b;
   126 	return path;
   127 }
   128 
   129 bool isInTmpDir(QString fn)
   130 {
   131 	QString temp=QDir::tempPath();
   132 	int l=temp.length();
   133 	return fn.left(l)==temp;
   134 }
   135 
   136 QString makeUniqueDir (bool &ok,QString s)
   137 {
   138 	// Create unique directory e.g. for s="/tmp/vym-XXXXXX"
   139 
   140 	// Convert Separators
   141 	s=QDir::convertSeparators(s);
   142 
   143 	// Convert QString to string 
   144 	ok=true;
   145 	char *p;
   146 	int bytes=s.length();
   147 	p=(char*) malloc (bytes+1);
   148 	int i;
   149 	for (i=0;i<bytes;i++)
   150 		p[i]=s.at(i).latin1();
   151 	p[bytes]=0;	
   152 
   153 	QString r=mkdtemp (p);
   154 	if (r.isEmpty()) ok=false;
   155 	free (p);
   156 	return r;
   157 }
   158 
   159 void removeDir(QDir d)
   160 {
   161 	// This check should_ not be necessary, but proved to be useful ;-)
   162 	if (!isInTmpDir(d.path()))
   163 	{
   164 		qWarning ("file.cpp::removeDir should remove "+d.path()+" - aborted.");
   165 		return;
   166 	}
   167 
   168 	// Traverse directories
   169 	d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
   170 	QFileInfoList list = d.entryInfoList();
   171 	QFileInfo fi;
   172 
   173 	for (int i = 0; i < list.size(); ++i) 
   174 	{
   175 		fi=list.at(i);
   176 		if (fi.fileName() != "." && fi.fileName() != ".." )
   177 		{
   178 			if ( !d.cd(fi.fileName()) ) 
   179 				qWarning ("removeDir() cannot find the directory "+fi.fileName());
   180 			else 
   181 			{
   182 				// Recursively remove subdirs
   183 				removeDir (d);
   184 				d.cdUp();
   185 			}
   186 		}	
   187 	}
   188 
   189 	// Traverse files
   190 	d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
   191 	list = d.entryInfoList();
   192 
   193 	for (int i = 0; i < list.size(); ++i) 
   194 	{
   195 		fi=list.at(i);
   196 		QFile (fi.filePath()).remove(); 
   197 	}	
   198 
   199 	if (!d.rmdir(d.path()))
   200 		qWarning ("removeDir("+d.path()+") failed!");
   201 }		
   202 
   203 void copyDir (QDir src, QDir dst)
   204 {
   205 	system ("cp -r "+src.path()+"/* "+dst.path());
   206 
   207 	/*
   208 	ErrorCode err=success;
   209 
   210 	Process *cpProc=new Process ();
   211 	QStringList args;
   212 	cpProc->setWorkingDirectory (src.path());
   213 	args <<"-r";
   214 	args <<src.path();
   215 	args <<dst.path();
   216 
   217 	cpProc->start ("cp",args);
   218 	if (!cpProc->waitForStarted() )
   219 	{	
   220 		// zip could not be started
   221 		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   222 					   QObject::tr("Couldn't start zip to compress data."));
   223 		err=aborted;
   224 	} else
   225 	{
   226 		// zip could be started
   227 		cpProc->waitForFinished();
   228 		if (cpProc->exitStatus()!=QProcess::NormalExit )
   229 		{
   230 			QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   231 						   QObject::tr("cp didn't exit normally")+
   232 						   "\n" + cpProc->getErrout());
   233 			err=aborted;
   234 		} else
   235 		{
   236 			if (cpProc->exitCode()>0)
   237 			{
   238 				QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   239 						   QString("cp exit code:  %1").arg(cpProc->exitCode() )+
   240 						   "\n" + cpProc->getErrout() );
   241 				err=aborted;
   242 			}
   243 		}
   244 	}	// cp could be started
   245 	*/
   246 }
   247 
   248 void makeSubDirs (const QString &s)
   249 {
   250 	QDir d(s);
   251 	d.mkdir(s);
   252 	d.mkdir ("images");	
   253 	d.mkdir ("flags");	
   254 }
   255 
   256 ErrorCode zipDir (const QDir &zipDir, const QString &zipName)
   257 {
   258 	ErrorCode err=success;
   259 	
   260 	// zip the temporary directory
   261 	QStringList args;
   262 	Process *zipProc=new Process ();
   263 	zipProc->setWorkingDirectory (zipDir.path());
   264 	args <<"-r";
   265 	args <<zipName;
   266 	args <<".";
   267 
   268 	zipProc->start ("zip",args);
   269 	if (!zipProc->waitForStarted() )
   270 	{	
   271 		// zip could not be started
   272 		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   273 					   QObject::tr("Couldn't start zip to compress data."));
   274 		err=aborted;
   275 	} else
   276 	{
   277 		// zip could be started
   278 		zipProc->waitForFinished();
   279 		if (zipProc->exitStatus()!=QProcess::NormalExit )
   280 		{
   281 			QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   282 						   QObject::tr("zip didn't exit normally")+
   283 						   "\n" + zipProc->getErrout());
   284 			err=aborted;
   285 		} else
   286 		{
   287 			if (zipProc->exitCode()>0)
   288 			{
   289 				QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   290 						   QString("zip exit code:  %1").arg(zipProc->exitCode() )+
   291 						   "\n" + zipProc->getErrout() );
   292 				err=aborted;
   293 			}
   294 		}
   295 	}	// zip could be started
   296 	return err;	
   297 }
   298 
   299 ErrorCode unzipDir (const QDir &zipDir, const QString &zipName)
   300 {
   301 	ErrorCode err=success;
   302 
   303 	// Try to unzip file
   304 #if !defined(Q_OS_WIN32)
   305 	QStringList args;
   306 	Process *zipProc=new Process ();
   307 	zipProc->setWorkingDirectory (zipDir.path());
   308 	args << "-o";	// overwrite existing files!
   309 	args << zipName ;
   310 	args << "-d";
   311 	args << zipDir.path();
   312 
   313 	zipProc->start ("unzip",args);
   314 	if (!zipProc->waitForStarted() )
   315 	{
   316 		QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   317 					   QObject::tr("Couldn't start unzip to decompress data."));
   318 		err=aborted;
   319 		
   320 	} else
   321 	{
   322 		zipProc->waitForFinished();
   323 		if (zipProc->exitStatus()!=QProcess::NormalExit )
   324 		{
   325 			QMessageBox::critical( 0,QObject::tr( "Critical Error" ),
   326 						   QObject::tr("unzip didn't exit normally") +
   327 						   zipProc->getErrout() );
   328 			err=aborted;
   329 		} else
   330 		{
   331 			if (zipProc->exitCode()>0)
   332 			{
   333 				if (zipProc->exitCode()==9)
   334 					// no zipped file, but maybe .xml or old version? Try again.
   335 					err=nozip;
   336 				else	
   337 				{
   338 					QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
   339 								   QString("unzip exit code:  %1").arg(zipProc->exitCode() ) +
   340 								   zipProc->getErrout() );
   341 					err=aborted;
   342 				}
   343 			} 
   344 		}
   345 	}
   346 #else
   347     // Do this process creation using Win32 API.
   348     //! Create process.
   349     PROCESS_INFORMATION piProcInfo;
   350     STARTUPINFO siStartInfo;
   351 
   352     // Initialize members of the PROCESS_INFORMATION structure.
   353     ::ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
   354 
   355     // Set up members of the STARTUPINFO structure.
   356     ::ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   357     siStartInfo.cb = sizeof(STARTUPINFO);
   358 
   359     // Create command line.
   360     QString argv("unzip -o ");
   361     argv.append(QDir::convertSeparators(zipName));
   362     argv.append(" -d ");
   363     argv.append(QDir::convertSeparators(zipDir.path()));
   364 
   365     // Create the child process.
   366     if( !::CreateProcess(NULL, 
   367         (LPWSTR)argv.unicode(), // command line
   368         NULL, // process security attributes
   369         NULL, // primary thread security attributes
   370         TRUE, // handles are inherited
   371         0, // creation flags
   372         NULL, // use parent's environment
   373         NULL, // use parent's current directory
   374         &siStartInfo, // STARTUPINFO pointer
   375         &piProcInfo) ) // receives PROCESS_INFORMATION
   376     {
   377         err = aborted;
   378     }
   379     else
   380     {
   381         // Wait for it to finish.
   382         ::WaitForSingleObject( piProcInfo.hProcess, 10000 );
   383     }
   384 #endif
   385 	return err;	
   386 }
   387 
   388 bool loadStringFromDisk (const QString &fname, QString &s)
   389 {
   390 	s="";
   391 	QFile file ( fname);
   392 	if ( !file.open( QIODevice::ReadOnly ) ) return false;
   393 
   394 	QTextStream ts( &file );
   395 	ts.setEncoding (QTextStream::UnicodeUTF8);
   396 	while ( !ts.atEnd() ) 
   397 		s+=ts.readLine()+"\n"; 
   398 	file.close();
   399 	return true;
   400 }
   401 
   402 bool saveStringToDisk (const QString &fname, const QString &s)
   403 {
   404 	QFile file( fname);
   405 
   406 	file.setName ( fname);
   407 	if ( !file.open( QIODevice::WriteOnly ) ) 
   408 	{
   409 		file.close();
   410 		return false;
   411 	}	
   412 
   413 	// Write it finally, and write in UTF8, no matter what 
   414 	QTextStream ts( &file );
   415 	ts.setEncoding (QTextStream::UnicodeUTF8);
   416 	ts << s;
   417 	file.close();
   418 	return true;
   419 }
   420 
   421 
   422 ImagePreview::ImagePreview (QWidget *par=0): QLabel (par)
   423 {
   424 	fdia=(Q3FileDialog*)par;
   425 }
   426 
   427 void ImagePreview::previewUrl( const Q3Url &u )
   428 {
   429     QString path = u.path();
   430     QPixmap pix( path );
   431     if ( pix.isNull() )
   432 	{
   433 		// Strange: If we have fd->setMode (QFileDialog::ExistingFiles)
   434 		// in the filedialog, then there are 3 calls to previewURL 
   435 		// for each selection. And only the first is the actual selected file
   436 		// while the following 2 point to the directory above the current one.
   437 		// So here's my workaround:
   438 		
   439 		if (fdia && fdia->selectedFiles().count()==0)
   440 			setText( QObject::tr("This is not an image.") );
   441 		if (fdia &&fdia->selectedFiles().count()>1)
   442 			setText( QObject::tr("Sorry, no preview for\nmultiple selected files.") );
   443 	}	
   444     else
   445 	{
   446 		float max_w=300;
   447 		float max_h=300;
   448 		float r;
   449 		if (pix.width()>max_w)
   450 		{
   451 			r=max_w / pix.width();
   452 			pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
   453 			// TODO not a resize, but a shrink/enlarge is needed here...
   454 		}
   455 		if (pix.height()>max_h)
   456 		{
   457 			r=max_h / pix.height();
   458 			pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
   459 			// TODO not a resize, but a shrink/enlarge is needed here...
   460 		}
   461         setPixmap( pix );
   462 	}	
   463 }
   464 
   465 ImageIO::ImageIO ()
   466 {
   467 	// Create list with supported image types
   468 	// foreach (QByteArray format, QImageWriter::supportedImageFormats()) 
   469 	// imageTypes.append( tr("%1...").arg(QString(format).toUpper()));
   470 	imageFilters.append ("Images (*.png *.jpg *.jpeg *.bmp *.bmp *.ppm *.xpm *.xbm)");
   471 	imageTypes.append ("PNG");
   472 	imageFilters.append ("Portable Network Graphics (*.png)");
   473 	imageTypes.append ("PNG");
   474 	imageFilters.append ("Joint Photographic Experts Group (*.jpg)");
   475 	imageTypes.append ("JPG");
   476 	imageFilters.append ("Joint Photographic Experts Group (*.jpeg)");
   477 	imageTypes.append ("JPG");
   478 	imageFilters.append ("Windows Bitmap (*.bmp)");
   479 	imageTypes.append ("BMP");
   480 	imageFilters.append ("Portable Pixmap (*.ppm)");
   481 	imageTypes.append ("PPM");
   482 	imageFilters.append ("X11 Bitmap (*.xpm)");
   483 	imageTypes.append ("XPM");
   484 	imageFilters.append ("X11 Bitmap (*.xbm)");
   485 	imageTypes.append ("XBM");
   486 }
   487 
   488 QStringList ImageIO::getFilters()
   489 {
   490 	return imageFilters;
   491 }
   492 
   493 QString ImageIO::getType(QString filter)
   494 {
   495 	for (int i=0;i<imageFilters.count()+1;i++)
   496 		if (imageFilters.at(i)==filter) return imageTypes.at(i);
   497 	return QString();	
   498 }
   499 
   500