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