Integrated file selection dialogue with the main code. Improved the
[openvpnui.git] / src / filebrowse / engine.cpp
diff --git a/src/filebrowse/engine.cpp b/src/filebrowse/engine.cpp
new file mode 100644 (file)
index 0000000..b5418e1
--- /dev/null
@@ -0,0 +1,353 @@
+#include "engine.h"
+#include <QDateTime>
+#include <QTextStream>
+#include <QSettings>
+#include <QStandardPaths>
+#include "globals.h"
+#include "fileworker.h"
+
+Engine::Engine(QObject *parent) :
+    QObject(parent),
+    m_clipboardContainsCopy(false),
+    m_progress(0),
+    m_selectedFilename(""),
+    m_extensionFilter("")
+{
+    m_fileWorker = new FileWorker;
+
+    // update progress property when worker progresses
+    connect(m_fileWorker, SIGNAL(progressChanged(int, QString)),
+            this, SLOT(setProgress(int, QString)));
+
+    // pass worker end signals to QML
+    connect(m_fileWorker, SIGNAL(done()), this, SIGNAL(workerDone()));
+    connect(m_fileWorker, SIGNAL(errorOccurred(QString, QString)),
+            this, SIGNAL(workerErrorOccurred(QString, QString)));
+    connect(m_fileWorker, SIGNAL(fileDeleted(QString)), this, SIGNAL(fileDeleted(QString)));
+}
+
+Engine::~Engine()
+{
+    // is this the way to force stop the worker thread?
+    m_fileWorker->cancel(); // stop possibly running background thread
+    m_fileWorker->wait();   // wait until thread stops
+    delete m_fileWorker;    // delete it
+}
+
+void Engine::deleteFiles(QStringList filenames)
+{
+    setProgress(0, "");
+    m_fileWorker->startDeleteFiles(filenames);
+}
+
+void Engine::cutFiles(QStringList filenames)
+{
+    m_clipboardFiles = filenames;
+    m_clipboardContainsCopy = false;
+    emit clipboardCountChanged();
+    emit clipboardContainsCopyChanged();
+}
+
+void Engine::copyFiles(QStringList filenames)
+{
+    m_clipboardFiles = filenames;
+    m_clipboardContainsCopy = true;
+    emit clipboardCountChanged();
+    emit clipboardContainsCopyChanged();
+}
+
+void Engine::pasteFiles(QString destDirectory)
+{
+    if (m_clipboardFiles.isEmpty()) {
+        emit workerErrorOccurred("No files to paste", "");
+        return;
+    }
+
+    QStringList files = m_clipboardFiles;
+    setProgress(0, "");
+
+    QDir dest(destDirectory);
+    if (!dest.exists()) {
+        emit workerErrorOccurred(tr("Destination does not exist"), destDirectory);
+        return;
+    }
+
+    foreach (QString filename, files) {
+        QFileInfo fileInfo(filename);
+        QString newname = dest.absoluteFilePath(fileInfo.fileName());
+
+        // source and dest filenames are the same?
+        if (filename == newname) {
+            emit workerErrorOccurred(tr("Can't overwrite itself"), newname);
+            return;
+        }
+
+        // dest is under source? (directory)
+        if (newname.startsWith(filename)) {
+            emit workerErrorOccurred(tr("Can't move/copy to itself"), filename);
+            return;
+        }
+    }
+
+    m_clipboardFiles.clear();
+    emit clipboardCountChanged();
+
+    if (m_clipboardContainsCopy) {
+        m_fileWorker->startCopyFiles(files, destDirectory);
+        return;
+    }
+
+    m_fileWorker->startMoveFiles(files, destDirectory);
+}
+
+void Engine::cancel()
+{
+    m_fileWorker->cancel();
+}
+
+QString Engine::homeFolder() const
+{
+    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
+}
+
+int Engine::startDepth() const
+{
+    return 2;
+}
+
+bool Engine::exists(QString filename)
+{
+    return QFile::exists(filename);
+}
+
+QStringList Engine::diskSpace(QString path)
+{
+    // run df to get disk space
+    QString blockSize = "--block-size=1024";
+    QString result = execute("/bin/df", QStringList() << blockSize << path, false);
+    if (result.isEmpty())
+        return QStringList();
+
+    // parse result
+    QStringList lines = result.split(QRegExp("[\n\r]"));
+    if (lines.count() < 2)
+        return QStringList();
+
+    QString line = lines.at(1);
+    QStringList columns = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
+    if (columns.count() < 5)
+        return QStringList();
+
+    QString totalString = columns.at(1);
+    QString usedString = columns.at(2);
+    QString percentageString = columns.at(4);
+    qint64 total = totalString.toLongLong() * 1024LL;
+    qint64 used = usedString.toLongLong() * 1024LL;
+
+    return QStringList() << percentageString << filesizeToString(used)+"/"+filesizeToString(total);
+}
+
+QStringList Engine::readFile(QString filename)
+{
+    int maxLines = 1000;
+    int maxSize = 10000;
+    int maxBinSize = 2048;
+
+    // check permissions
+    if (access(filename, R_OK) == -1)
+        return makeStringList(tr("No permission to read the file\n%1").arg(filename));
+
+    QFile file(filename);
+    if (!file.open(QIODevice::ReadOnly))
+        return makeStringList(tr("Error reading file\n%1").arg(filename));
+
+    // read start of file
+    char buffer[maxSize+1];
+    qint64 readSize = file.read(buffer, maxSize);
+    if (readSize < 0)
+        return makeStringList(tr("Error reading file\n%1").arg(filename));
+
+    if (readSize == 0)
+        return makeStringList(tr("Empty file"));
+
+    bool atEnd = file.atEnd();
+    file.close();
+
+    // detect binary or text file, it is binary if it contains zeros
+    bool isText = true;
+    for (int i = 0; i < readSize; ++i) {
+        if (buffer[i] == 0) {
+            isText = false;
+            break;
+        }
+    }
+
+    // binary output
+    if (!isText) {
+        // two different line widths
+        if (readSize > maxBinSize) {
+            readSize = maxBinSize;
+            atEnd = false;
+        }
+        QString out8 = createHexDump(buffer, readSize, 8);
+        QString out16 = createHexDump(buffer, readSize, 16);
+        QString msg = "";
+
+        if (!atEnd) {
+            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1000);
+            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1000);
+        }
+
+        return QStringList() << msg << out8 << out16;
+    }
+
+    // read lines to a string list and join
+    QByteArray ba(buffer, readSize);
+    QTextStream in(&ba);
+    QStringList lines;
+    int lineCount = 0;
+    while (!in.atEnd() && lineCount < maxLines) {
+        QString line = in.readLine();
+        lines.append(line);
+        lineCount++;
+    }
+
+    QString msg = "";
+    if (lineCount == maxLines)
+        msg = tr("--- Text file preview clipped at %1 lines ---").arg(maxLines);
+    else if (!atEnd)
+        msg = tr("--- Text file preview clipped at %1 kB ---").arg(maxSize/1000);
+
+    return makeStringList(msg, lines.join("\n"));
+}
+
+QString Engine::mkdir(QString path, QString name)
+{
+    QDir dir(path);
+
+    if (!dir.mkdir(name)) {
+        if (access(dir.absolutePath(), W_OK) == -1)
+            return tr("Cannot create folder %1\nPermission denied").arg(name);
+
+        return tr("Cannot create folder %1").arg(name);
+    }
+
+    return QString();
+}
+
+QStringList Engine::rename(QString fullOldFilename, QString newName)
+{
+    QFile file(fullOldFilename);
+    QFileInfo fileInfo(fullOldFilename);
+    QDir dir = fileInfo.absoluteDir();
+    QString fullNewFilename = dir.absoluteFilePath(newName);
+
+    QString errorMessage;
+    if (!file.rename(fullNewFilename)) {
+        QString oldName = fileInfo.fileName();
+        errorMessage = tr("Cannot rename %1\n%2").arg(oldName).arg(file.errorString());
+    }
+
+    return QStringList() << fullNewFilename << errorMessage;
+}
+
+QString Engine::chmod(QString path,
+                      bool ownerRead, bool ownerWrite, bool ownerExecute,
+                      bool groupRead, bool groupWrite, bool groupExecute,
+                      bool othersRead, bool othersWrite, bool othersExecute)
+{
+    QFile file(path);
+    QFileDevice::Permissions p;
+    if (ownerRead) p |= QFileDevice::ReadOwner;
+    if (ownerWrite) p |= QFileDevice::WriteOwner;
+    if (ownerExecute) p |= QFileDevice::ExeOwner;
+    if (groupRead) p |= QFileDevice::ReadGroup;
+    if (groupWrite) p |= QFileDevice::WriteGroup;
+    if (groupExecute) p |= QFileDevice::ExeGroup;
+    if (othersRead) p |= QFileDevice::ReadOther;
+    if (othersWrite) p |= QFileDevice::WriteOther;
+    if (othersExecute) p |= QFileDevice::ExeOther;
+    if (!file.setPermissions(p))
+        return tr("Cannot change permissions\n%1").arg(file.errorString());
+
+    return QString();
+}
+
+QString Engine::readSetting(QString key, QString defaultValue)
+{
+    QSettings settings;
+    return settings.value(key, defaultValue).toString();
+}
+
+void Engine::writeSetting(QString key, QString value)
+{
+    QSettings settings;
+
+    // do nothing if value didn't change
+    if (settings.value(key) == value)
+        return;
+
+    settings.setValue(key, value);
+
+    emit settingsChanged();
+}
+
+void Engine::setProgress(int progress, QString filename)
+{
+    m_progress = progress;
+    m_progressFilename = filename;
+    emit progressChanged();
+    emit progressFilenameChanged();
+}
+
+QString Engine::createHexDump(char *buffer, int size, int bytesPerLine)
+{
+    QString out;
+    QString ascDump;
+    int i;
+    for (i = 0; i < size; ++i) {
+        if ((i % bytesPerLine) == 0) { // line change
+            out += " "+ascDump+"\n"+
+                    QString("%1").arg(QString::number(i, 16), 4, QLatin1Char('0'))+": ";
+            ascDump.clear();
+        }
+
+        out += QString("%1").arg(QString::number((unsigned char)buffer[i], 16),
+                                       2, QLatin1Char('0'))+" ";
+        if (buffer[i] >= 32 && buffer[i] <= 126)
+            ascDump += buffer[i];
+        else
+            ascDump += ".";
+    }
+    // write out remaining asc dump
+    if ((i % bytesPerLine) > 0) {
+        int emptyBytes = bytesPerLine - (i % bytesPerLine);
+        for (int j = 0; j < emptyBytes; ++j) {
+            out += "   ";
+        }
+    }
+    out += " "+ascDump;
+
+    return out;
+}
+
+QStringList Engine::makeStringList(QString msg, QString str)
+{
+    QStringList list;
+    list << msg << str << str;
+    return list;
+}
+
+void Engine::setSelectedFilename(QString selectedFilename)
+{
+    m_selectedFilename = selectedFilename;
+    emit selectedFilenameChanged();
+}
+
+void Engine::setExtensionFilter(QString extensionFilter)
+{
+    if (m_extensionFilter != extensionFilter) {
+        m_extensionFilter = extensionFilter;
+        emit extensionFilterChanged();
+    }
+}