initial import
[vym] / file.cpp
diff --git a/file.cpp b/file.cpp
new file mode 100644 (file)
index 0000000..01fecb2
--- /dev/null
+++ b/file.cpp
@@ -0,0 +1,500 @@
+#include <QDir>
+#include <QMessageBox>
+#include <QPixmap>
+#include <QLabel>
+#include <QTextStream>
+#include <iostream>
+#include <QUrl>
+
+#include "file.h"
+#include "process.h"
+
+#if defined(Q_OS_WIN32)
+#include "mkdtemp.h"
+#include <windows.h>
+#endif
+
+QString maskPath(QString p)
+{
+       // Change " " to "\ " to enable blanks in filenames
+       p=p.replace(QChar('&'),"\\&");
+       return p.replace(QChar(' '),"\\ ");
+}
+
+QString convertToRel (const QString &src, const QString &dst)
+{
+       QString s=src;
+       QString d=dst;
+       int i;
+
+       if (s==d) 
+       {
+               // Special case, we just need the name of the file,
+               // not the complete path
+               i=d.findRev ("/");
+               d=d.right (d.length()-i-1);
+       } else
+       {
+               // Find relative path from src to dst
+
+               // Remove the first "/"
+               if (s.section ("/",0,0).isEmpty()) 
+               {
+                       s=s.right (s.length()-1);
+                       d=d.right (d.length()-1);
+               }
+               
+               // remove identical left parts
+               while (s.section("/",0,0) == d.section("/",0,0) ) 
+               {
+                       i=s.find ("/");
+                       s=s.right (s.length()-i-1);
+                       d=d.right (d.length()-i-1);
+               }
+
+               // Now take care of paths where we have to go back first
+               int srcsep=s.count("/");
+               int dstsep=d.count("/");
+               if (srcsep <=  dstsep )
+               {
+                       // find path to go up first and then back to dst
+                       i=1;
+                       while (i<=srcsep) 
+                       {
+                               d="../"+d;
+                               i++;
+                       }       
+               }
+       }       
+       return d;
+}
+
+#include <QFileDialog>
+extern QString vymName;
+extern QDir lastFileDir;
+
+QString browseDirectory (QWidget *parent,const QString &caption)
+{
+       QFileDialog fd(parent,caption);
+       fd.setMode (QFileDialog::DirectoryOnly);
+       fd.setCaption(vymName+ " - "+caption);
+       fd.setDir (lastFileDir);
+       fd.show();
+       
+       if ( fd.exec() == QDialog::Accepted )
+               return fd.selectedFile();
+       else
+               return "";
+}
+
+
+
+bool reallyWriteDirectory(const QString &dir)
+{
+       QStringList eList = QDir(dir).entryList();
+       if (eList.first() ==".")  eList.pop_front();    // remove "."
+       if (eList.first() =="..") eList.pop_front();    // remove "."
+       if (!eList.isEmpty())
+       {
+               QMessageBox mb( vymName,
+                       QObject::tr("The directory %1 is not empty.\nDo you risk to overwrite its contents?","write directory").arg(dir),
+               QMessageBox::Warning,
+               QMessageBox::Yes ,
+               QMessageBox::Cancel | QMessageBox::Default,
+               QMessageBox::NoButton );
+
+               mb.setButtonText( QMessageBox::Yes, QObject::tr("Overwrite") );
+               mb.setButtonText( QMessageBox::No, QObject::tr("Cancel"));
+               switch( mb.exec() ) 
+               {
+                       case QMessageBox::Yes:
+                               // save 
+                               return true;
+                       case QMessageBox::Cancel:
+                               // do nothing
+                               return false;
+               }
+       }
+       return true;
+}
+
+QString makeTmpDir (bool &ok, QString prefix)
+{
+       bool b;
+       QString path=makeUniqueDir (b,QDir::tempPath()+"/"+prefix+"-XXXXXX");
+       ok=b;
+       return path;
+}
+
+bool isInTmpDir(QString fn)
+{
+       QString temp=QDir::tempPath();
+       int l=temp.length();
+       return fn.left(l)==temp;
+}
+
+QString makeUniqueDir (bool &ok,QString s)
+{
+       // Create unique directory e.g. for s="/tmp/vym-XXXXXX"
+
+       // Convert Separators
+       s=QDir::convertSeparators(s);
+
+       // Convert QString to string 
+       ok=true;
+       char *p;
+       int bytes=s.length();
+       p=(char*) malloc (bytes+1);
+       int i;
+       for (i=0;i<bytes;i++)
+               p[i]=s.at(i).latin1();
+       p[bytes]=0;     
+
+       QString r=mkdtemp (p);
+       if (r.isEmpty()) ok=false;
+       free (p);
+       return r;
+}
+
+void removeDir(QDir d)
+{
+       // This check should_ not be necessary, but proved to be useful ;-)
+       if (!isInTmpDir(d.path()))
+       {
+               qWarning ("file.cpp::removeDir should remove "+d.path()+" - aborted.");
+               return;
+       }
+
+       // Traverse directories
+       d.setFilter( QDir::Dirs| QDir::Hidden | QDir::NoSymLinks );
+       QFileInfoList list = d.entryInfoList();
+       QFileInfo fi;
+
+       for (int i = 0; i < list.size(); ++i) 
+       {
+               fi=list.at(i);
+               if (fi.fileName() != "." && fi.fileName() != ".." )
+               {
+                       if ( !d.cd(fi.fileName()) ) 
+                               qWarning ("removeDir() cannot find the directory "+fi.fileName());
+                       else 
+                       {
+                               // Recursively remove subdirs
+                               removeDir (d);
+                               d.cdUp();
+                       }
+               }       
+       }
+
+       // Traverse files
+       d.setFilter( QDir::Files| QDir::Hidden | QDir::NoSymLinks );
+       list = d.entryInfoList();
+
+       for (int i = 0; i < list.size(); ++i) 
+       {
+               fi=list.at(i);
+               QFile (fi.filePath()).remove(); 
+       }       
+
+       if (!d.rmdir(d.path()))
+               qWarning ("removeDir("+d.path()+") failed!");
+}              
+
+void copyDir (QDir src, QDir dst)
+{
+       system ("cp -r "+src.path()+"/* "+dst.path());
+
+       /*
+       ErrorCode err=success;
+
+       Process *cpProc=new Process ();
+       QStringList args;
+       cpProc->setWorkingDirectory (src.path());
+       args <<"-r";
+       args <<src.path();
+       args <<dst.path();
+
+       cpProc->start ("cp",args);
+       if (!cpProc->waitForStarted() )
+       {       
+               // zip could not be started
+               QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                          QObject::tr("Couldn't start zip to compress data."));
+               err=aborted;
+       } else
+       {
+               // zip could be started
+               cpProc->waitForFinished();
+               if (cpProc->exitStatus()!=QProcess::NormalExit )
+               {
+                       QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                                  QObject::tr("cp didn't exit normally")+
+                                                  "\n" + cpProc->getErrout());
+                       err=aborted;
+               } else
+               {
+                       if (cpProc->exitCode()>0)
+                       {
+                               QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                                  QString("cp exit code:  %1").arg(cpProc->exitCode() )+
+                                                  "\n" + cpProc->getErrout() );
+                               err=aborted;
+                       }
+               }
+       }       // cp could be started
+       */
+}
+
+void makeSubDirs (const QString &s)
+{
+       QDir d(s);
+       d.mkdir(s);
+       d.mkdir ("images");     
+       d.mkdir ("flags");      
+}
+
+ErrorCode zipDir (const QDir &zipDir, const QString &zipName)
+{
+       ErrorCode err=success;
+       
+       // zip the temporary directory
+       QStringList args;
+       Process *zipProc=new Process ();
+       zipProc->setWorkingDirectory (zipDir.path());
+       args <<"-r";
+       args <<zipName;
+       args <<".";
+
+       zipProc->start ("zip",args);
+       if (!zipProc->waitForStarted() )
+       {       
+               // zip could not be started
+               QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                          QObject::tr("Couldn't start zip to compress data."));
+               err=aborted;
+       } else
+       {
+               // zip could be started
+               zipProc->waitForFinished();
+               if (zipProc->exitStatus()!=QProcess::NormalExit )
+               {
+                       QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                                  QObject::tr("zip didn't exit normally")+
+                                                  "\n" + zipProc->getErrout());
+                       err=aborted;
+               } else
+               {
+                       if (zipProc->exitCode()>0)
+                       {
+                               QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                                  QString("zip exit code:  %1").arg(zipProc->exitCode() )+
+                                                  "\n" + zipProc->getErrout() );
+                               err=aborted;
+                       }
+               }
+       }       // zip could be started
+       return err;     
+}
+
+ErrorCode unzipDir (const QDir &zipDir, const QString &zipName)
+{
+       ErrorCode err=success;
+
+       // Try to unzip file
+#if !defined(Q_OS_WIN32)
+       QStringList args;
+       Process *zipProc=new Process ();
+       zipProc->setWorkingDirectory (zipDir.path());
+       args << "-o";   // overwrite existing files!
+       args << zipName ;
+       args << "-d";
+       args << zipDir.path();
+
+       zipProc->start ("unzip",args);
+       if (!zipProc->waitForStarted() )
+       {
+               QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                          QObject::tr("Couldn't start unzip to decompress data."));
+               err=aborted;
+               
+       } else
+       {
+               zipProc->waitForFinished();
+               if (zipProc->exitStatus()!=QProcess::NormalExit )
+               {
+                       QMessageBox::critical( 0,QObject::tr( "Critical Error" ),
+                                                  QObject::tr("unzip didn't exit normally") +
+                                                  zipProc->getErrout() );
+                       err=aborted;
+               } else
+               {
+                       if (zipProc->exitCode()>0)
+                       {
+                               if (zipProc->exitCode()==9)
+                                       // no zipped file, but maybe .xml or old version? Try again.
+                                       err=nozip;
+                               else    
+                               {
+                                       QMessageBox::critical( 0, QObject::tr( "Critical Error" ),
+                                                                  QString("unzip exit code:  %1").arg(zipProc->exitCode() ) +
+                                                                  zipProc->getErrout() );
+                                       err=aborted;
+                               }
+                       } 
+               }
+       }
+#else
+    // Do this process creation using Win32 API.
+    //! Create process.
+    PROCESS_INFORMATION piProcInfo;
+    STARTUPINFO siStartInfo;
+
+    // Initialize members of the PROCESS_INFORMATION structure.
+    ::ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
+
+    // Set up members of the STARTUPINFO structure.
+    ::ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
+    siStartInfo.cb = sizeof(STARTUPINFO);
+
+    // Create command line.
+    QString argv("unzip -o ");
+    argv.append(QDir::convertSeparators(zipName));
+    argv.append(" -d ");
+    argv.append(QDir::convertSeparators(zipDir.path()));
+
+    // Create the child process.
+    if( !::CreateProcess(NULL, 
+        (LPWSTR)argv.unicode(), // command line
+        NULL, // process security attributes
+        NULL, // primary thread security attributes
+        TRUE, // handles are inherited
+        0, // creation flags
+        NULL, // use parent's environment
+        NULL, // use parent's current directory
+        &siStartInfo, // STARTUPINFO pointer
+        &piProcInfo) ) // receives PROCESS_INFORMATION
+    {
+        err = aborted;
+    }
+    else
+    {
+        // Wait for it to finish.
+        ::WaitForSingleObject( piProcInfo.hProcess, 10000 );
+    }
+#endif
+       return err;     
+}
+
+bool loadStringFromDisk (const QString &fname, QString &s)
+{
+       s="";
+       QFile file ( fname);
+       if ( !file.open( QIODevice::ReadOnly ) ) return false;
+
+       QTextStream ts( &file );
+       ts.setEncoding (QTextStream::UnicodeUTF8);
+       while ( !ts.atEnd() ) 
+               s+=ts.readLine()+"\n"; 
+       file.close();
+       return true;
+}
+
+bool saveStringToDisk (const QString &fname, const QString &s)
+{
+       QFile file( fname);
+
+       file.setName ( fname);
+       if ( !file.open( QIODevice::WriteOnly ) ) 
+       {
+               file.close();
+               return false;
+       }       
+
+       // Write it finally, and write in UTF8, no matter what 
+       QTextStream ts( &file );
+       ts.setEncoding (QTextStream::UnicodeUTF8);
+       ts << s;
+       file.close();
+       return true;
+}
+
+
+ImagePreview::ImagePreview (QWidget *par=0): QLabel (par)
+{
+        fdia=(QFileDialog*)par;
+}
+
+void ImagePreview::previewUrl( const QUrl &u )
+{
+    QString path = u.path();
+    QPixmap pix( path );
+    if ( pix.isNull() )
+       {
+               // Strange: If we have fd->setMode (QFileDialog::ExistingFiles)
+               // in the filedialog, then there are 3 calls to previewURL 
+               // for each selection. And only the first is the actual selected file
+               // while the following 2 point to the directory above the current one.
+               // So here's my workaround:
+               
+               if (fdia && fdia->selectedFiles().count()==0)
+                       setText( QObject::tr("This is not an image.") );
+               if (fdia &&fdia->selectedFiles().count()>1)
+                       setText( QObject::tr("Sorry, no preview for\nmultiple selected files.") );
+       }       
+    else
+       {
+               float max_w=300;
+               float max_h=300;
+               float r;
+               if (pix.width()>max_w)
+               {
+                       r=max_w / pix.width();
+                       pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
+                       // TODO not a resize, but a shrink/enlarge is needed here...
+               }
+               if (pix.height()>max_h)
+               {
+                       r=max_h / pix.height();
+                       pix.resize(qRound(pix.width()*r), qRound(pix.height()*r));
+                       // TODO not a resize, but a shrink/enlarge is needed here...
+               }
+        setPixmap( pix );
+       }       
+}
+
+ImageIO::ImageIO ()
+{
+       // Create list with supported image types
+       // foreach (QByteArray format, QImageWriter::supportedImageFormats()) 
+       // imageTypes.append( tr("%1...").arg(QString(format).toUpper()));
+       imageFilters.append ("Images (*.png *.jpg *.jpeg *.bmp *.bmp *.ppm *.xpm *.xbm)");
+       imageTypes.append ("PNG");
+       imageFilters.append ("Portable Network Graphics (*.png)");
+       imageTypes.append ("PNG");
+       imageFilters.append ("Joint Photographic Experts Group (*.jpg)");
+       imageTypes.append ("JPG");
+       imageFilters.append ("Joint Photographic Experts Group (*.jpeg)");
+       imageTypes.append ("JPG");
+       imageFilters.append ("Windows Bitmap (*.bmp)");
+       imageTypes.append ("BMP");
+       imageFilters.append ("Portable Pixmap (*.ppm)");
+       imageTypes.append ("PPM");
+       imageFilters.append ("X11 Bitmap (*.xpm)");
+       imageTypes.append ("XPM");
+       imageFilters.append ("X11 Bitmap (*.xbm)");
+       imageTypes.append ("XBM");
+}
+
+QStringList ImageIO::getFilters()
+{
+       return imageFilters;
+}
+
+QString ImageIO::getType(QString filter)
+{
+       for (int i=0;i<imageFilters.count()+1;i++)
+               if (imageFilters.at(i)==filter) return imageTypes.at(i);
+       return QString();       
+}
+
+