the big bang
authorLukas Hrazky <lukkash@email.cz>
Tue, 13 Jul 2010 21:42:57 +0000 (23:42 +0200)
committerLukas Hrazky <lukkash@email.cz>
Tue, 13 Jul 2010 21:42:57 +0000 (23:42 +0200)
Signed-off-by: Lukas Hrazky <lukkash@email.cz>

15 files changed:
.gitignore [new file with mode: 0644]
case.pro [new file with mode: 0644]
src/addressbar.cpp [new file with mode: 0644]
src/addressbar.h [new file with mode: 0644]
src/button.cpp [new file with mode: 0644]
src/button.h [new file with mode: 0644]
src/case.cpp [new file with mode: 0644]
src/case.h [new file with mode: 0644]
src/filelist.cpp [new file with mode: 0644]
src/filelist.h [new file with mode: 0644]
src/fileoperator.cpp [new file with mode: 0644]
src/fileoperator.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/pane.cpp [new file with mode: 0644]
src/pane.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..8672cdf
--- /dev/null
@@ -0,0 +1,3 @@
+case
+Makefile
+.build
diff --git a/case.pro b/case.pro
new file mode 100644 (file)
index 0000000..26bd047
--- /dev/null
+++ b/case.pro
@@ -0,0 +1,30 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Mon Jul 12 22:30:42 2010
+######################################################################
+
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += . src
+INCLUDEPATH += . src
+
+# added manually!
+CONFIG += link_pkgconfig
+PKGCONFIG += dbus-1 gnome-vfs-2.0
+LIBS += -lhildonmime -ldbus-1
+OBJECTS_DIR=.build
+MOC_DIR=.build
+
+# Input
+HEADERS += src/addressbar.h \
+           src/button.h \
+           src/case.h \
+           src/filelist.h \
+           src/fileoperator.h \
+           src/pane.h
+SOURCES += src/addressbar.cpp \
+           src/button.cpp \
+           src/case.cpp \
+           src/filelist.cpp \
+           src/fileoperator.cpp \
+           src/main.cpp \
+           src/pane.cpp
diff --git a/src/addressbar.cpp b/src/addressbar.cpp
new file mode 100644 (file)
index 0000000..e0145a4
--- /dev/null
@@ -0,0 +1,37 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "addressbar.h"
+
+
+AddressBar::AddressBar(QWidget *parent) : QLineEdit(parent) {
+    setMaximumHeight(60);
+    setContentsMargins(-4, -4, -4, -4);
+
+    connect(this, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+}
+
+
+void AddressBar::mousePressEvent(QMouseEvent *event) {
+    emit mousePressed();
+    QLineEdit::mousePressEvent(event);
+}
+
+
+void AddressBar::returnPressed() {
+    emit pathEntered(text());
+}
diff --git a/src/addressbar.h b/src/addressbar.h
new file mode 100644 (file)
index 0000000..11fec38
--- /dev/null
@@ -0,0 +1,41 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef ADDRESSBAR_H
+#define ADDRESSBAR_H
+
+#include <QLineEdit>
+
+
+class AddressBar : public QLineEdit {
+    Q_OBJECT;
+
+signals:
+    void mousePressed();
+    void pathEntered(QString path);
+
+public:
+    explicit AddressBar(QWidget *parent = 0);
+
+protected:
+    void mousePressEvent(QMouseEvent *event);
+
+protected slots:
+    void returnPressed();
+};
+
+#endif // ADDRESSBAR_H
diff --git a/src/button.cpp b/src/button.cpp
new file mode 100644 (file)
index 0000000..19e78a3
--- /dev/null
@@ -0,0 +1,38 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "button.h"
+
+
+Button::Button(QWidget *parent, const int maxWidth, const int maxHeight) : QPushButton(parent) {
+    setMaximumWidth(maxWidth);
+    setMaximumHeight(maxHeight);
+}
+
+Button::Button(const QString &text, QWidget *parent, const int maxWidth, const int maxHeight) :
+    QPushButton(text, parent)
+{
+    setMaximumWidth(maxWidth);
+    setMaximumHeight(maxHeight);
+}
+
+Button::Button(const QIcon &icon, const QString &text, QWidget *parent, const int maxWidth, const int maxHeight) :
+    QPushButton(icon, text, parent)
+{
+    setMaximumWidth(maxWidth);
+    setMaximumHeight(maxHeight);
+}
diff --git a/src/button.h b/src/button.h
new file mode 100644 (file)
index 0000000..1379c1f
--- /dev/null
@@ -0,0 +1,33 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef BUTTON_H
+#define BUTTON_H
+
+#include <QPushButton>
+
+
+class Button : public QPushButton {
+    Q_OBJECT
+
+public:
+    explicit Button(QWidget *parent = 0, int maxWidth = 70, int maxHeight = 70);
+    explicit Button(const QString &text, QWidget *parent = 0, const int maxWidth = 70, const int maxHeight = 70);
+    explicit Button(const QIcon &icon, const QString &text, QWidget *parent = 0, const int maxWidth = 70, const int maxHeight = 70);
+};
+
+#endif // BUTTON_H
diff --git a/src/case.cpp b/src/case.cpp
new file mode 100644 (file)
index 0000000..b3163ba
--- /dev/null
@@ -0,0 +1,132 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "case.h"
+
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+
+
+Case::Case(QWidget *parent) :
+    QMainWindow(parent),
+    leftPane(new Pane(this)),
+    rightPane(new Pane(this)),
+    activePane(leftPane),
+    inactivePane(rightPane),
+    cloneBtn(new Button(">>", 0, 60, 70)),
+    moveBtn(new Button("mv>", 0, 60, 70)),
+    copyBtn(new Button("cp>", 0, 60, 70)),
+    delBtn(new Button("rm", 0, 60, 70)),
+    swapBtn(new Button("<>", 0, 60, 70)),
+    fileOperator(new FileOperator(this))
+{
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->setSpacing(0);
+
+    QHBoxLayout *paneLayout = new QHBoxLayout;
+    paneLayout->setContentsMargins(0, 0, 0, 0);
+    paneLayout->setSpacing(1);
+
+    QWidget *central = new QWidget;
+    setCentralWidget(central);
+    central->setLayout(layout);
+    layout->addLayout(paneLayout);
+
+    paneLayout->addWidget(leftPane);
+    leftPane->toggleActive();
+
+    QVBoxLayout *middleButtons = new QVBoxLayout;
+    paneLayout->addLayout(middleButtons);
+    middleButtons->setSpacing(10);
+    middleButtons->setContentsMargins(0, 0, 0, 0);
+
+    cloneBtn->setContentsMargins(0, 0, 0, 0);
+
+    middleButtons->addWidget(cloneBtn);
+    middleButtons->addWidget(moveBtn);
+    middleButtons->addWidget(copyBtn);
+    middleButtons->addWidget(delBtn);
+    middleButtons->addWidget(swapBtn);
+
+    paneLayout->addWidget(rightPane);
+
+    layout->addWidget(fileOperator);
+
+    connect(this, SIGNAL(activePaneSwitched()), leftPane, SLOT(toggleActive()));
+    connect(this, SIGNAL(activePaneSwitched()), rightPane, SLOT(toggleActive()));
+
+    connect(cloneBtn, SIGNAL(pressed()), this, SLOT(clonePane()));
+    connect(delBtn, SIGNAL(pressed()), this, SLOT(deleteFiles()));
+    connect(copyBtn, SIGNAL(pressed()), this, SLOT(copyFiles()));
+    connect(moveBtn, SIGNAL(pressed()), this, SLOT(moveFiles()));
+    connect(swapBtn, SIGNAL(pressed()), this, SLOT(swapPanes()));
+}
+
+
+void Case::switchActivePane() {
+    Pane *tmpPane = activePane;
+    activePane = inactivePane;
+    inactivePane = tmpPane;
+
+    if (leftPane == activePane) {
+        cloneBtn->setText(">>");
+        moveBtn->setText("mv>");
+        copyBtn->setText("cp>");
+    } else {
+        cloneBtn->setText("<<");
+        moveBtn->setText("<mv");
+        copyBtn->setText("<cp");
+    }
+
+    emit activePaneSwitched();
+}
+
+
+void Case::deleteFiles() {
+    if (activePane->selection().size()) {
+        fileOperator->deleteFiles(activePane->selection());
+    }
+}
+
+
+void Case::copyFiles() {
+    if (activePane->selection().size()) {
+        QDir dest = inactivePane->path();
+        fileOperator->copyFiles(activePane->selection(), dest);
+    }
+}
+
+
+void Case::moveFiles() {
+    if (activePane->selection().size()) {
+        QDir dest = inactivePane->path();
+        fileOperator->moveFiles(activePane->selection(), dest);
+    }
+}
+
+
+void Case::clonePane() {
+    inactivePane->changePath(activePane->path());
+}
+
+
+void Case::swapPanes() {
+    QString tmpPath = activePane->path();
+    activePane->changePath(inactivePane->path());
+    inactivePane->changePath(tmpPath);
+}
diff --git a/src/case.h b/src/case.h
new file mode 100644 (file)
index 0000000..aee7cbb
--- /dev/null
@@ -0,0 +1,54 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef CASE_H
+#define CASE_H
+
+#include "pane.h"
+#include "fileoperator.h"
+#include "button.h"
+
+#include <QMainWindow>
+#include <QEvent>
+
+
+class Case : public QMainWindow {
+    Q_OBJECT
+
+signals:
+    void activePaneSwitched();
+
+public:
+    Case(QWidget *parent = 0);
+
+public slots:
+    void switchActivePane();
+
+private:
+    Pane *leftPane, *rightPane, *activePane, *inactivePane;
+    Button *cloneBtn, *moveBtn, *copyBtn, *delBtn, *swapBtn;
+    FileOperator *fileOperator;
+
+private slots:
+    void deleteFiles();
+    void copyFiles();
+    void moveFiles();
+    void clonePane();
+    void swapPanes();
+};
+
+#endif // CASE_H
diff --git a/src/filelist.cpp b/src/filelist.cpp
new file mode 100644 (file)
index 0000000..8bba30e
--- /dev/null
@@ -0,0 +1,101 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "filelist.h"
+
+#include <QProcess>
+#include <QUrl>
+
+#include <hildon-mime.h>
+#include <dbus/dbus.h>
+
+
+FileList::FileList(QWidget *parent) :
+    QListView(parent),
+    fileSystemModel(new QFileSystemModel)
+{
+    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+    //setSelectionMode(QAbstractItemView::SingleSelection);
+    setSelectionMode(QAbstractItemView::MultiSelection);
+
+    setModel(fileSystemModel);
+
+    fileSystemModel->setFilter(fileSystemModel->filter() | QDir::System);
+    setRootIndex(fileSystemModel->setRootPath(QDir::homePath()));
+
+    connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(activateItem(QModelIndex)));
+}
+
+
+const QFileInfoList FileList::selection() const {
+    QFileInfoList files;
+    QModelIndexList l = selectionModel()->selectedIndexes();
+    for (int i = 0; i < l.size(); ++i) {
+        files.append(fileSystemModel->fileInfo(l[i]));
+    }
+    return files;
+}
+
+
+const QString FileList::path() const {
+    return fileSystemModel->rootPath();
+}
+
+
+bool FileList::changePath(QString path) {
+    QDir dir(fileSystemModel->rootPath());
+    if (dir.cd(path)) {
+        setRootIndex(fileSystemModel->setRootPath(dir.absolutePath()));
+        clearSelection();
+        emit pathChanged(fileSystemModel->rootPath());
+        return true;
+    }
+
+    return false;
+}
+
+
+bool FileList::goUp() {
+    return changePath("..");
+}
+
+
+void FileList::activateItem(QModelIndex index) {
+    const QFileInfo &file = fileSystemModel->fileInfo(index);
+
+    if(file.isDir()) {
+        changePath(file.absoluteFilePath());
+    } else if(file.isExecutable()) {
+        QProcess::startDetached(file.absoluteFilePath());
+    } else {
+        // TODO: find better solution for this, maybe get fixed in Qt
+        DBusConnection* conn;
+        conn = dbus_bus_get(DBUS_BUS_SESSION, 0);
+        hildon_mime_open_file(conn, QUrl::fromLocalFile(file.absoluteFilePath()).toEncoded().constData());
+
+        // Not working with maemo5. Uses hildon_uri_open function from
+        // libhildonmime which should work, but all files opened in browser.
+        //QDesktopServices::openUrl(QUrl::fromLocalFile(file.absoluteFilePath()));
+    }
+}
+
+
+void FileList::mousePressEvent(QMouseEvent *event) {
+    emit mousePressed();
+    QListView::mousePressEvent(event);
+}
diff --git a/src/filelist.h b/src/filelist.h
new file mode 100644 (file)
index 0000000..8e5a5c4
--- /dev/null
@@ -0,0 +1,52 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef FILELIST_H
+#define FILELIST_H
+
+#include <QListView>
+#include <QFileInfoList>
+#include <QFileSystemModel>
+
+
+class FileList : public QListView {
+    Q_OBJECT;
+
+signals:
+    void mousePressed();
+    void pathChanged(QString path);
+
+public:
+    explicit FileList(QWidget *parent = 0);
+
+    const QFileInfoList selection() const;
+    const QString path() const;
+
+public slots:
+    bool changePath(QString path);
+    bool goUp();
+
+protected:
+    QFileSystemModel *fileSystemModel;
+
+    void mousePressEvent(QMouseEvent *event);
+
+private slots:
+    void activateItem(QModelIndex index);
+};
+
+#endif // FILELIST_H
diff --git a/src/fileoperator.cpp b/src/fileoperator.cpp
new file mode 100644 (file)
index 0000000..2aa8265
--- /dev/null
@@ -0,0 +1,705 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "fileoperator.h"
+
+#include <QtGui>
+#include <QDir>
+#include <QMessageBox>
+#include <QHBoxLayout>
+#include <QChar>
+
+#include <math.h>
+#include <errno.h>
+#include <iostream>
+
+
+#define SHOW_ERROR_PROMPT(promptString)                                                 \
+    response = FileOperator::NONE;                                                      \
+    if (ignoreAll[errno]) {                                                             \
+        response = FileOperator::IGNORE;                                                \
+    } else {                                                                            \
+        char buf[255];                                                                  \
+        char *realBuf = strerror_r(errno, buf, 255);                                    \
+        emit showErrorPrompt(this, promptString + ". " + realBuf + ".", errno);         \
+        waitCond.wait(&mutex);                                                          \
+    }
+
+
+#define ERROR_PROMPT(operation, promptString)                                           \
+{                                                                                       \
+    response = FileOperator::NONE;                                                      \
+    while (!abort && operation) {                                                       \
+        SHOW_ERROR_PROMPT(promptString)                                                 \
+        if (response == FileOperator::IGNORE) {                                         \
+            break;                                                                      \
+        }                                                                               \
+    }                                                                                   \
+}
+
+
+#define ERROR_PROMPT_XP(operation, promptString, onIgnore, quitCmd)                     \
+{                                                                                       \
+    ERROR_PROMPT(operation, promptString)                                               \
+    if (abort || response == FileOperator::IGNORE) {                                    \
+        if (!abort) onIgnore;                                                           \
+        quitCmd;                                                                        \
+    }                                                                                   \
+}
+
+
+#define OVERWRITE_PROMPT(file, newFile)                                                 \
+{                                                                                       \
+    response = FileOperator::NONE;                                                      \
+                                                                                        \
+    if (newFile.exists()) {                                                             \
+        if (overwriteAll != FileOperator::NONE) {                                       \
+            response = overwriteAll;                                                    \
+        } else {                                                                        \
+            bool dirOverDir = false;                                                    \
+            if (newFile.isDir() && file.isDir()) dirOverDir = true;                     \
+            emit showOverwritePrompt(this, newFile.absoluteFilePath(), dirOverDir);     \
+            waitCond.wait(&mutex);                                                      \
+        }                                                                               \
+    }                                                                                   \
+}
+
+
+FileOperator::FileOperator(QWidget *parent) : QWidget(parent) {
+    QHBoxLayout *layout = new QHBoxLayout;
+    layout->setContentsMargins(0, 0, 0, 0);
+    layout->setSpacing(0);
+    setLayout(layout);
+}
+
+
+void FileOperator::deleteFiles(const QFileInfoList &files) {
+    QString title, desc;
+    if (files.size() == 1) {
+        title = tr("Delete file");
+        desc = tr("Are you sure you want to delete %1?").arg(files[0].absoluteFilePath());
+    } else {
+        title = tr("Delete files");
+        desc = tr("You are about to delete %1 files. Are you sure you want to continue?").arg(files.size());
+    }
+
+    int confirm = QMessageBox::warning(
+        0,
+        title,
+        desc,
+        QMessageBox::Yes,
+        QMessageBox::No
+    );
+
+    if(confirm == QMessageBox::Yes) {
+        caterNewThread(new DeleteThread(files));
+    }
+}
+
+
+void FileOperator::copyFiles(const QFileInfoList &files, QDir &destination) {
+    QString title, desc;
+    if (files.size() == 1) {
+        title = tr("Copy file");
+        desc = tr("Are you sure you want to copy %1 to %2?").arg(files[0].absoluteFilePath())
+            .arg(destination.absolutePath());
+    } else {
+        title = tr("Copy files");
+        desc = tr("You are about to copy %1 files to %2. Are you sure you want to continue?")
+            .arg(files.size()).arg(destination.absolutePath());
+    }
+
+    int confirm = QMessageBox::warning(
+        0,
+        title,
+        desc,
+        QMessageBox::Yes,
+        QMessageBox::No
+    );
+
+    if(confirm == QMessageBox::Yes) {
+        caterNewThread(new CopyThread(files, destination));
+    }
+}
+
+
+void FileOperator::moveFiles(const QFileInfoList &files, QDir &destination) {
+    // for move we don't wanna move to the same dir
+    if (files[0].absolutePath() == destination.absolutePath()) return;
+
+    QString title, desc;
+    if (files.size() == 1) {
+        title = tr("Move file");
+        desc = tr("Are you sure you want to move %1 to %2?").arg(files[0].absoluteFilePath())
+            .arg(destination.absolutePath());
+    } else {
+        title = tr("Move files");
+        desc = tr("You are about to move %1 files to %2. Are you sure you want to continue?")
+            .arg(files.size()).arg(destination.absolutePath());
+    }
+
+    int confirm = QMessageBox::warning(
+        0,
+        title,
+        desc,
+        QMessageBox::Yes,
+        QMessageBox::No
+    );
+
+    if(confirm == QMessageBox::Yes) {
+        caterNewThread(new MoveThread(files, destination));
+    }
+}
+
+
+void FileOperator::showErrorPrompt(FileManipulatorThread* manipulator, const QString &message, const int err) {
+    QMessageBox msgBox;
+    msgBox.addButton(QMessageBox::Cancel);
+    QAbstractButton *abortButton = msgBox.addButton(tr("Abort"), QMessageBox::DestructiveRole);
+    QAbstractButton *retryButton = msgBox.addButton(QMessageBox::Retry);
+    QAbstractButton *ignoreButton = msgBox.addButton(QMessageBox::Ignore);
+    QAbstractButton *ignoreAllButton = msgBox.addButton(tr("Ignore All"), QMessageBox::AcceptRole);
+    msgBox.setText(message);
+
+    msgBox.exec();
+
+    if (msgBox.clickedButton() == abortButton) {
+        manipulator->setResponse(ABORT);
+    } else if (msgBox.clickedButton() == retryButton) {
+        manipulator->setResponse(RETRY);
+    } else if (msgBox.clickedButton() == ignoreButton) {
+        manipulator->setResponse(IGNORE);
+    } else if (msgBox.clickedButton() == ignoreAllButton) {
+        manipulator->setResponse(IGNORE, true, err);
+    }
+}
+
+
+void FileOperator::showOverwritePrompt(
+    FileManipulatorThread* manipulator,
+    const QString &fileName,
+    const bool dirOverDir)
+{
+    QMessageBox msgBox;
+    msgBox.addButton(QMessageBox::Cancel);
+    QAbstractButton *yesButton = msgBox.addButton(QMessageBox::Yes);
+    QAbstractButton *yesToAllButton = msgBox.addButton(QMessageBox::YesToAll);
+    QAbstractButton *noButton = msgBox.addButton(QMessageBox::No);
+    QAbstractButton *noToAllButton = msgBox.addButton(QMessageBox::NoToAll);
+    QAbstractButton *abortButton = msgBox.addButton(tr("Abort"), QMessageBox::DestructiveRole);
+    QAbstractButton *askButton = 0;
+
+    if (dirOverDir) {
+        msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?").arg(fileName));
+        askButton = msgBox.addButton(tr("Ask"), QMessageBox::AcceptRole);
+    } else {
+        msgBox.setText(tr("File %1 already exists. Overwrite?").arg(fileName));
+    }
+
+    msgBox.exec();
+
+    if (msgBox.clickedButton() == abortButton) {
+        manipulator->setResponse(ABORT);
+    } else if (msgBox.clickedButton() == yesButton) {
+        manipulator->setResponse(OVERWRITE);
+    } else if (msgBox.clickedButton() == yesToAllButton) {
+        manipulator->setResponse(OVERWRITE, true);
+    } else if (msgBox.clickedButton() == noButton) {
+        manipulator->setResponse(KEEP);
+    } else if (msgBox.clickedButton() == noToAllButton) {
+        manipulator->setResponse(KEEP, true);
+    } else if (msgBox.clickedButton() == askButton) {
+        manipulator->setResponse(NONE, true);
+    }
+}
+
+
+void FileOperator::remove(FileManipulatorThread* manipulator) {
+    layout()->removeWidget(manipulator->widget);
+    manipulatorList.removeAll(manipulator);
+    delete manipulator;
+}
+
+
+void FileOperator::setBarSize(FileManipulatorThread* manipulator, unsigned int size) {
+    manipulator->widget->setMinimum(0);
+    manipulator->widget->setMaximum(size);
+}
+
+
+void FileOperator::updateProgress(FileManipulatorThread* manipulator, int value) {
+    if (manipulator->widget->value() + value > manipulator->widget->maximum()) {
+        std::cout << "WARNING, EXCEEDING MAXIMUM BY " << value << std::endl;
+    }
+    manipulator->widget->setValue(manipulator->widget->value() + value);
+}
+
+
+void FileOperator::caterNewThread(FileManipulatorThread *thread) {
+    manipulatorList.append(thread);
+
+    connect(thread, SIGNAL(showErrorPrompt(FileManipulatorThread*, const QString&, const int)),
+        this, SLOT(showErrorPrompt(FileManipulatorThread*, const QString&, const int)));
+    connect(thread, SIGNAL(showOverwritePrompt(FileManipulatorThread*, const QString&, bool)),
+        this, SLOT(showOverwritePrompt(FileManipulatorThread*, const QString&, bool)));
+    connect(thread, SIGNAL(finished(FileManipulatorThread*)),
+        this, SLOT(remove(FileManipulatorThread*)));
+    connect(thread, SIGNAL(setBarSize(FileManipulatorThread*, unsigned int)),
+        this, SLOT(setBarSize(FileManipulatorThread*, unsigned int)));
+    connect(thread, SIGNAL(updateProgress(FileManipulatorThread*, int)),
+        this, SLOT(updateProgress(FileManipulatorThread*, int)));
+
+    thread->widget->setValue(0);
+
+    layout()->addWidget(thread->widget);
+    thread->start();
+}
+
+
+FileManipulatorThread::FileManipulatorThread(const QFileInfoList files, QDir dest) :
+    widget(new QProgressBar()),
+    files(files),
+    dest(dest),
+    response(FileOperator::NONE),
+    overwriteAll(FileOperator::NONE),
+    abort(false),
+    barSize(0),
+    barValue(0),
+    fileSize(0),
+    fileValue(0)
+{
+    memset(ignoreAll, false, sizeof(ignoreAll));
+    //widget->setStyle(new QPlastiqueStyle);
+}
+
+
+void FileManipulatorThread::setResponse(
+    const FileOperator::Response response,
+    const bool applyToAll,
+    const int err)
+{
+    mutex.lock();
+
+    this->response = response;
+
+    if (applyToAll) {
+        if (response == FileOperator::KEEP
+            || response == FileOperator::OVERWRITE
+            || response == FileOperator::NONE)
+        {
+            overwriteAll = response;
+        }
+
+        if (response == FileOperator::IGNORE) {
+            ignoreAll[err] = true;
+        }
+    }
+
+    if (response == FileOperator::ABORT) abort = true;
+
+    mutex.unlock();
+    waitCond.wakeAll();
+}
+
+
+void FileManipulatorThread::processFiles(const QFileInfoList &files) {
+    for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
+        perform(*it);
+        if (abort) break;
+    }
+}
+
+
+bool FileManipulatorThread::remove(QString &fileName, const bool ignoreDirNotEmpty) {
+    return remove(QFileInfo(fileName), ignoreDirNotEmpty);
+}
+
+
+bool FileManipulatorThread::remove(const QFileInfoList &files, const bool ignoreDirNotEmpty) {
+    bool res = true;
+    for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
+        if (!remove(*it, ignoreDirNotEmpty)) res = false;
+        if (abort) break;
+    }
+    return res;
+}
+
+
+bool FileManipulatorThread::remove(const QFileInfo &file, const bool ignoreDirNotEmpty) {
+    QString path = file.absoluteFilePath();
+    QFSFileEngine engine(path);
+
+    if (file.isDir()) {
+        QFileInfoList list = listDirFiles(path);
+
+        if (ignoreDirNotEmpty && list.size()) return true;
+
+        if (!remove(list, ignoreDirNotEmpty)) return false;
+
+        ERROR_PROMPT(!engine.rmdir(path, false),
+            tr("Error deleting directory %1.").arg(path))
+    } else {
+        ERROR_PROMPT(!engine.remove(),
+            tr("Error deleting file %1.").arg(path))
+    }
+
+    if (abort || response == FileOperator::IGNORE) return false;
+    return true;
+}
+
+
+void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCopy) {
+    std::cout << (removeAfterCopy ? "MOVING " : "COPYING ") << file.absoluteFilePath().toStdString()
+        << " to " << dest.absolutePath().toStdString() << std::endl;
+
+    QString path(file.absoluteFilePath());
+    QString newPath(dest.absolutePath() + "/" + file.fileName());
+    QFSFileEngine engine(path);
+    QFSFileEngine newEngine(newPath);
+    QFileInfo newFile(newPath);
+
+    updateFile(path);
+
+    // hack to prevent asking about the same file if we already asked in the rename(...) function
+    if (overwriteAll == FileOperator::DONT_ASK_ONCE) {
+        overwriteAll = FileOperator::NONE;
+    } else {
+        OVERWRITE_PROMPT(file, newFile)
+    }
+
+    if (abort) return;
+
+    // this loop is here only to allow easily breaking out to the end (and remove the source file/dir)
+    while (1) {
+        if (response == FileOperator::KEEP) {
+            updateProgress(fileSizeMap[path]);
+            break;
+        }
+
+        FileOperator::Response overwriteResponse = response;
+
+        if (file.isDir()) {
+            if (newFile.exists() && !newFile.isDir()) {
+                if(!remove(newPath)) {
+                    updateProgress(fileSizeMap[path]);
+                    break;
+                }
+                newFile = QFileInfo(newPath);
+            }
+
+            if (!newFile.exists()) {
+                ERROR_PROMPT_XP(!engine.mkdir(newPath, false),
+                    tr("Error creating directory %1.").arg(newPath),
+                    updateProgress(fileSizeMap[path]),
+                    break)
+            }
+
+            updateProgress(1);
+            
+            QDir destBackup = dest;
+            dest = newPath;
+
+            FileOperator::Response tmpResp = overwriteAll;
+            overwriteAll = overwriteResponse;
+
+            processFiles(listDirFiles(path));
+
+            overwriteAll = tmpResp;
+
+            ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
+                tr("Error setting permissions for directory %1.").arg(newPath))
+
+            if (abort) return;
+
+            dest = destBackup;
+        } else {
+            ERROR_PROMPT_XP(engine.isSequential(),
+                tr("Cannot copy sequential file %1.").arg(path),
+                updateProgress(fileSizeMap[path]),
+                break)
+
+            if (newFile.exists() && newFile.isDir()) {
+                ERROR_PROMPT_XP(!remove(newPath),
+                    tr("Cannot replace directory %1 due to previous errors.").arg(newPath),
+                    updateProgress(fileSizeMap[path]),
+                    break)
+            }
+
+            ERROR_PROMPT_XP(!engine.open(QIODevice::ReadOnly),
+                tr("Error reading file %1.").arg(path),
+                updateProgress(fileSizeMap[path]),
+                break)
+
+            bool ignore = false;
+            while (!abort && !ignore) {
+                engine.seek(0);
+
+                ERROR_PROMPT(!newEngine.open(QIODevice::WriteOnly | QIODevice::Truncate),
+                    tr("Error writing file %1.").arg(newPath))
+
+                if (abort || response == FileOperator::IGNORE) {
+                    if (response == FileOperator::IGNORE) {
+                        updateProgress(fileSizeMap[path] - fileValue);
+                        ignore = true;
+                    }
+                    break;
+                }
+
+                bool error = false;
+                char block[4096];
+                qint64 bytes;
+                while ((bytes = engine.read(block, sizeof(block))) > 0) {
+                    if (bytes == -1 || bytes != newEngine.write(block, bytes)) {
+                        if (bytes == -1) {
+                            SHOW_ERROR_PROMPT(tr("Error while reading from file %1.").arg(path));
+                        } else {
+                            SHOW_ERROR_PROMPT(tr("Error while writing to file %1.").arg(newPath));
+                        }
+
+                        if (!abort) {
+                            if (response == FileOperator::IGNORE) {
+                                updateProgress(fileSizeMap[path] - fileValue);
+                                ignore = true;
+                            } else {
+                                updateProgress(-fileValue);
+                            }
+                        }
+                        error = true;
+                        break;
+                    }
+
+                    updateProgress(1);
+                }
+
+                if (!error) break;
+            }
+
+            engine.close();
+            newEngine.close();
+
+            if (abort || ignore) {
+                newEngine.remove();
+            } else {
+                ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
+                    tr("Error setting permissions for file %1.").arg(newPath))
+            }
+        }
+
+        break;
+    }
+
+    if (removeAfterCopy && !abort) remove(path, true);
+}
+
+
+unsigned int FileManipulatorThread::countFiles(const QFileInfoList &files) {
+    unsigned int res = 0;
+
+    for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
+        unsigned int size = 1;
+
+        if (it->isDir()) {
+            size += countFiles(listDirFiles(it->absoluteFilePath()));
+        }
+
+        res += size;
+        fileSizeMap[it->absoluteFilePath()] = size;
+    }
+
+    return res;
+}
+
+
+unsigned int FileManipulatorThread::calculateFileSize(const QFileInfoList &files) {
+    unsigned int res = 0;
+
+    for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
+        unsigned int size = 1;
+
+        if (it->isDir()) {
+            size += calculateFileSize(listDirFiles(it->absoluteFilePath()));
+        } else {
+            size = ceil(static_cast<float>(it->size()) / 4096);
+        }
+
+        res += size;
+        fileSizeMap[it->absoluteFilePath()] = size;
+    }
+
+    return res;
+}
+
+
+QFileInfoList FileManipulatorThread::listDirFiles(const QString &dirPath) {
+    QDir dir = dirPath;
+    return dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System | QDir::Hidden);
+}
+
+
+void FileManipulatorThread::setBarSize(unsigned int size) {
+    barSize = size;
+    emit setBarSize(this, size);
+}
+
+
+void FileManipulatorThread::updateProgress(int value) {
+    barValue += value;
+    fileValue += value;
+    emit updateProgress(this, value);
+}
+
+
+void FileManipulatorThread::updateFile(const QString &fileName) {
+    fileValue = 0;
+    emit updateFile(this, fileName);
+}
+
+
+void DeleteThread::run() {
+    mutex.lock();
+
+    setBarSize(countFiles(files));
+
+    processFiles(files);
+
+    sleep(0.5);
+    emit finished(this);
+}
+
+
+void DeleteThread::perform(const QFileInfo &file) {
+    std::cout << "DELETING " << file.absoluteFilePath().toStdString() << std::endl;
+
+    QString path = file.absoluteFilePath();
+    QFSFileEngine engine(path);
+
+    if (file.isDir()) {
+        processFiles(listDirFiles(path));
+
+        if (!listDirFiles(path).size()) {
+            ERROR_PROMPT(!engine.rmdir(path, false),
+                tr("Error deleting directory %1.").arg(path))
+        }
+    } else {
+        ERROR_PROMPT(!engine.remove(),
+            tr("Error deleting file %1.").arg(path))
+    }
+
+    if (!abort) updateProgress(1);
+}
+
+
+void CopyThread::run() {
+    mutex.lock();
+
+    setBarSize(calculateFileSize(files));
+
+    processFiles(files);
+
+    sleep(0.5);
+    emit finished(this);
+}
+
+
+void CopyThread::perform(const QFileInfo &file) {
+    copy(file, false);
+}
+
+
+void MoveThread::run() {
+    mutex.lock();
+
+    rename(files, dest);
+
+    sleep(0.5);
+    emit finished(this);
+}
+
+
+void MoveThread::rename(const QFileInfoList &files, const QDir &dest) {
+    setBarSize(barSize + files.size());
+
+    for (int i = 0; i < files.size(); ++i) {
+        QString path = files[i].absoluteFilePath();
+        QFSFileEngine engine(path);
+        QString newPath = dest.absolutePath() + "/" + files[i].fileName();
+
+        updateFile(path);
+
+        OVERWRITE_PROMPT(files[i], QFileInfo(newPath))
+
+        if (response == FileOperator::KEEP) {
+            remove(path);
+            if (abort) break;
+            updateProgress(1);
+            continue;
+        }
+
+        while (!abort && !engine.rename(newPath)) {
+            // source and target are on different partitions
+            // this should happen on the first file, unless some are skipped by overwrite prompt
+            // we calculate the actual file sizes, because from now on copy & remove takes over
+            if (errno == EXDEV) {
+                setBarSize(barValue + calculateFileSize(files));
+
+                FileOperator::Response tmpResp = overwriteAll;
+                overwriteAll = response;
+                // hack: we already checked the first file we are sending to processFiles(...)
+                // so we don't want to ask about this one again
+                if (overwriteAll == FileOperator::NONE) overwriteAll = FileOperator::DONT_ASK_ONCE;
+
+                processFiles(files.mid(i));
+
+                overwriteAll = tmpResp;
+
+                // just to quit the loops, we are done
+                abort = true;
+            // the target is nonempty dir. lets call this recursively and rename the contents one by one
+            } else if (errno == ENOTEMPTY || errno == EEXIST) {
+                FileOperator::Response tmpResp = overwriteAll;
+                overwriteAll = response;
+
+                rename(listDirFiles(path), QDir(newPath));
+                if (abort) break;
+
+                overwriteAll = tmpResp;
+
+                ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1.").arg(path))
+
+                break;
+            // source and target are nonmatching types(file and dir)
+            // remove the target and let it loop once again
+            } else if (errno == ENOTDIR || errno == EISDIR) {
+                if (!remove(newPath)) break;
+            } else {
+                SHOW_ERROR_PROMPT(tr("Error moving %1.").arg(path))
+
+                if (response == FileOperator::IGNORE) {
+                    break;
+                }
+            }
+        }
+            
+        if (abort) break;
+        updateProgress(1);
+    }
+}
+
+
+void MoveThread::perform(const QFileInfo &file) {
+    copy(file, true);
+}
diff --git a/src/fileoperator.h b/src/fileoperator.h
new file mode 100644 (file)
index 0000000..7d53bfb
--- /dev/null
@@ -0,0 +1,151 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef FILEOPERATOR_H
+#define FILEOPERATOR_H
+
+#include <QWidget>
+#include <QProgressBar>
+#include <QFileInfo>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QDir>
+#include <QMap>
+
+
+class FileManipulatorThread;
+
+
+class FileOperator : public QWidget {
+    Q_OBJECT
+
+public:
+    // DONT_ASK_ONCE is a hackish way to avoid asking twice to overwrite the same directory when moving
+    enum Response{NONE, ABORT, RETRY, IGNORE, KEEP, OVERWRITE, DONT_ASK_ONCE};
+
+    FileOperator(QWidget *parent = 0);
+
+    void deleteFiles(const QFileInfoList &files);
+    void copyFiles(const QFileInfoList &files, QDir &destination);
+    void moveFiles(const QFileInfoList &files, QDir &destination);
+
+public slots:
+    void showErrorPrompt(FileManipulatorThread* manipulator, const QString &message, const int err);
+    void showOverwritePrompt(FileManipulatorThread* manipulator, const QString &fileName, const bool dirOverDir);
+    void remove(FileManipulatorThread* manipulator);
+    void setBarSize(FileManipulatorThread* manipulator, unsigned int size);
+    void updateProgress(FileManipulatorThread* manipulator, int value);
+
+protected:
+    void caterNewThread(FileManipulatorThread *thread);
+
+    QList<FileManipulatorThread*> manipulatorList;
+};
+
+
+class FileManipulatorThread : public QThread {
+    Q_OBJECT
+
+public:
+    explicit FileManipulatorThread(const QFileInfoList files, QDir dest = QDir());
+    void setResponse(const FileOperator::Response response, const bool appyToAll = false, const int err = 0);
+
+    QProgressBar *widget;
+
+protected:
+    void processFiles(const QFileInfoList &files);
+    virtual void perform(const QFileInfo &file) = 0;
+
+    bool remove(QString &filename, const bool ignoreDirNotEmpty = false);
+    bool remove(const QFileInfoList &files, const bool ignoreDirNotEmpty = false);
+    bool remove(const QFileInfo &file, const bool ignoreDirNotEmpty = false);
+
+    void copy(const QFileInfo &file, const bool removeAfterCopy);
+
+    unsigned int countFiles(const QFileInfoList &files);
+    unsigned int calculateFileSize(const QFileInfoList &files);
+
+    QFileInfoList listDirFiles(const QString &dirPath);
+
+    void setBarSize(unsigned int size);
+    void updateProgress(int value);
+    void updateFile(const QString &fileName);
+
+    const QFileInfoList files;
+    QDir dest;
+
+    FileOperator::Response response;
+    FileOperator::Response overwriteAll;
+    bool abort;
+    bool ignoreAll[256];
+
+    QMap<QString, qint64> fileSizeMap;
+
+    QMutex mutex;
+    QWaitCondition waitCond;
+
+    unsigned int barSize, barValue, fileSize, fileValue;
+
+signals:
+    void showErrorPrompt(FileManipulatorThread*, const QString&, const int);
+    void showOverwritePrompt(FileManipulatorThread*, const QString&, const bool);
+    void finished(FileManipulatorThread*);
+    void setBarSize(FileManipulatorThread*, unsigned int);
+    void updateProgress(FileManipulatorThread*, int);
+    void updateFile(FileManipulatorThread*, const QString&);
+};
+
+
+class DeleteThread : public FileManipulatorThread {
+    Q_OBJECT
+
+public:
+    explicit DeleteThread(const QFileInfoList &files) : FileManipulatorThread(files) {}
+
+protected:
+    void run();
+    virtual void perform(const QFileInfo &file);
+};
+
+
+class CopyThread : public FileManipulatorThread {
+    Q_OBJECT
+
+public:
+    explicit CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {}
+
+protected:
+    void run();
+    virtual void perform(const QFileInfo &file);
+};
+
+
+class MoveThread : public FileManipulatorThread {
+    Q_OBJECT
+
+public:
+    explicit MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {}
+
+protected:
+    void run();
+    virtual void perform(const QFileInfo &file);
+    void rename(const QFileInfoList &files, const QDir &dest);
+};
+
+
+#endif // FILEOPERATOR_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..8a7ba40
--- /dev/null
@@ -0,0 +1,29 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include <QApplication>
+
+#include "case.h"
+
+
+int main(int argc, char* argv[]) {
+    QApplication app(argc, argv);
+    Case theCase;
+
+    theCase.show();
+    return app.exec();
+}
diff --git a/src/pane.cpp b/src/pane.cpp
new file mode 100644 (file)
index 0000000..68b556f
--- /dev/null
@@ -0,0 +1,108 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#include "pane.h"
+
+#include <QHeaderView>
+#include <QVBoxLayout>
+#include <QMessageBox>
+#include <QInputDialog>
+#include <QDesktopServices>
+#include <QUrl>
+#include <QProcess>
+#include <QPainter>
+
+
+Pane::Pane(QWidget *theCase, QWidget *parent) :
+    QWidget(parent),
+    theCase(theCase),
+    active(false),
+    location(new AddressBar),
+    up(new Button("^", 0, 70, 60)),
+    fileList(new FileList)
+{
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->setContentsMargins(3, 3, 3, 3);
+    layout->setSpacing(0);
+    setLayout(layout);
+
+    QHBoxLayout *topLine = new QHBoxLayout;
+
+    location->setText(fileList->path());
+    layout->setSpacing(0);
+
+    topLine->addWidget(location);
+    topLine->addWidget(up);
+    layout->addLayout(topLine);
+    layout->addWidget(fileList);
+
+    connect(location, SIGNAL(pathEntered(QString)), fileList, SLOT(changePath(QString)));
+    connect(up, SIGNAL(pressed()), fileList, SLOT(goUp()));
+    connect(fileList, SIGNAL(pathChanged(QString)), location, SLOT(setText(QString)));
+
+    activationConnect();
+}
+
+
+void Pane::paintEvent(QPaintEvent *) {
+    if (active) {
+        QPainter painter(this);
+        painter.setPen(palette().color(QPalette::Highlight));
+        QRect g = this->geometry();
+        g.moveTo(1, 1);
+        g.setWidth(g.width() - 3);
+        g.setHeight(g.height() - 3);
+        painter.drawRect(g);
+    }
+}
+
+
+void Pane::activationConnect() {
+    connect(up, SIGNAL(clicked()), theCase, SLOT(switchActivePane()));
+    connect(location, SIGNAL(mousePressed()), theCase, SLOT(switchActivePane()));
+    connect(fileList, SIGNAL(mousePressed()), theCase, SLOT(switchActivePane()));
+}
+
+
+void Pane::activationDisconnect() {
+    disconnect(up, SIGNAL(clicked()), theCase, SLOT(switchActivePane()));
+    disconnect(location, SIGNAL(mousePressed()), theCase, SLOT(switchActivePane()));
+    disconnect(fileList, SIGNAL(mousePressed()), theCase, SLOT(switchActivePane()));
+}
+
+
+void Pane::toggleActive() {
+    active = !active;
+    if (active) activationDisconnect(); else activationConnect();
+    update();
+}
+
+
+const QFileInfoList Pane::selection() const {
+    return fileList->selection();
+}
+
+
+bool Pane::changePath(QString path) {
+    location->setText(path);
+    return fileList->changePath(path);
+}
+
+
+const QString Pane::path() const {
+    return fileList->path();
+}
diff --git a/src/pane.h b/src/pane.h
new file mode 100644 (file)
index 0000000..7489468
--- /dev/null
@@ -0,0 +1,58 @@
+// case - file manager for N900
+// Copyright (C) 2010 Lukas Hrazky
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+#ifndef PANE_H
+#define PANE_H
+
+#include <QFileInfoList>
+#include <QDir>
+
+#include "button.h"
+#include "filelist.h"
+#include "addressbar.h"
+
+
+class Pane : public QWidget {
+    Q_OBJECT
+
+public:
+    explicit Pane(QWidget *theCase, QWidget *parent = 0);
+
+    const QString path() const;
+    const QFileInfoList selection() const;
+
+public slots:
+    bool changePath(QString path);
+    void toggleActive();
+
+protected:
+    void paintEvent(QPaintEvent *);
+
+    void activationConnect();
+    void activationDisconnect();
+
+private:
+    QWidget *theCase;
+
+    bool active;
+
+    AddressBar *location;
+    Button *up;
+    FileList *fileList;
+};
+
+#endif // PANE_H