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 +