Commit 0294f2e7 authored by camilo higuita's avatar camilo higuita

initial work on the file manager for nomad, it is now functional

parents
function bookmarkFolder(path)
{
inx.bookmark(path)
placesSidebar.populate()
}
#include "index.h"
#include <QFileInfo>
#include <QMimeType>
#include <QDirIterator>
#include <QDesktopServices>
#include <QUrl>
#include <QStorageInfo>
#include "inx.h"
Index::Index(QObject *parent) : QObject(parent)
{
}
QVariantList Index::getPathContent(const QString &path)
{
QVariantList content;
if (QFileInfo(path).isDir())
{
QDirIterator it(path, QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot, QDirIterator::NoIteratorFlags);
while (it.hasNext())
{
auto url = it.next();
QFileInfo file(url);
QVariantMap item =
{
{"iconName", INX::getIconName(url)},
{"label", file.isDir() ? file.baseName() : file.baseName() + "."+file.suffix()},
{"path", url}
};
content << item;
}
}
return content;
}
QVariantList Index::getDefaultPaths()
{
return packItems(INX::defaultPaths, "Places");
}
bool Index::isDefaultPath(const QString &path)
{
return INX::defaultPaths.contains(path);
}
QVariantList Index::getDevices()
{
QVariantList drives;
auto devices = QStorageInfo::mountedVolumes();
for(auto device : devices)
{
if(device.isValid() && !device.isReadOnly())
{
QVariantMap drive =
{
{"iconName", "drive-harddisk"},
{"label", device.displayName()},
{"path", device.rootPath()},
{"type", "Drives"}
};
drives << drive;
}
}
return drives;
}
QString Index::homePath()
{
return INX::HomePath;
}
QString Index::parentDir(const QString &path)
{
auto dir = QDir(path);
dir.cdUp();
return dir.absolutePath();
}
bool Index::isDir(const QString &path)
{
return QFileInfo(path).isDir();
}
bool Index::openFile(const QString &path)
{
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
bool Index::bookmark(const QString &path)
{
auto bookmarks = INX::loadSettings("BOOKMARKS", "INX", QStringList()).toStringList();
bookmarks.append(path);
INX::saveSettings("BOOKMARKS", bookmarks, "INX");
return true;
}
QVariantList Index::getBookmarks()
{
auto bookmarks = INX::loadSettings("BOOKMARKS", "INX", QStringList()).toStringList();
return packItems(bookmarks, "Bookmarks");
}
QVariantList Index::packItems(const QStringList &items, const QString &type)
{
QVariantList data;
for(auto path : items)
data << getDirInfo(path, type);
return data;
}
QVariantMap Index::getDirInfo(const QString &path, const QString &type)
{
QFileInfo file (path);
QVariantMap data =
{
{"iconName", INX::getIconName(path)},
{"label", file.baseName()},
{"path", path},
{"type", type}
};
return data;
}
void Index::saveSettings(const QString &key, const QVariant &value, const QString &group)
{
INX::saveSettings(key, value, group);
}
QVariant Index::loadSettings(const QString &key, const QString &group, const QVariant &defaultValue)
{
return INX::loadSettings(key, group, defaultValue);
}
#ifndef INDEX_H
#define INDEX_H
#include <QObject>
#include <QVariantList>
#include <QStringList>
class Index : public QObject
{
Q_OBJECT
public:
explicit Index(QObject *parent = nullptr);
Q_INVOKABLE static QVariantList getPathContent(const QString &path);
Q_INVOKABLE static QVariantList getDefaultPaths();
Q_INVOKABLE static bool isDefaultPath(const QString &path);
Q_INVOKABLE static QVariantList getDevices();
Q_INVOKABLE static QString homePath();
Q_INVOKABLE static QString parentDir(const QString &path);
Q_INVOKABLE static bool isDir(const QString &path);
Q_INVOKABLE static bool openFile(const QString &path);
Q_INVOKABLE static bool bookmark(const QString &path);
Q_INVOKABLE static QVariantList getBookmarks();
Q_INVOKABLE static QVariantList packItems(const QStringList &items, const QString &type);
Q_INVOKABLE static void saveSettings(const QString &key, const QVariant &value, const QString &group);
Q_INVOKABLE static QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue);
Q_INVOKABLE static QVariantMap getDirInfo(const QString &path, const QString &type);
signals:
public slots:
};
#endif // INDEX_H
QT += qml quick quickcontrols2 sql widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp \
index.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
index.h \
inx.h
#ifndef INX_H
#define INX_H
#include <QString>
#include <QDebug>
#include <QStandardPaths>
#include <QFileInfo>
#include <QImage>
#include <QTime>
#include <QSettings>
#include <QDirIterator>
#include <QVariantList>
#include <QMimeType>
#include <QMimeData>
#include <QMimeDatabase>
namespace INX
{
Q_NAMESPACE
inline QString getNameFromLocation(const QString &str)
{
QString ret;
int index = 0;
for(int i = str.size() - 1; i >= 0; i--)
if(str[i] == '/')
{
index = i + 1;
i = -1;
}
for(; index < str.size(); index++)
ret.push_back(str[index]);
return ret;
}
const QString PicturesPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
const QString DownloadsPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
const QString DocumentsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
const QString HomePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
const QString MusicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
const QString VideosPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
const QString DesktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
const QStringList defaultPaths = {HomePath, DocumentsPath, MusicPath, VideosPath,PicturesPath, DownloadsPath, DesktopPath};
const QMap<QString, QString> folderIcon
{
{PicturesPath, "folder-pictures"},
{DownloadsPath, "folder-download"},
{DocumentsPath, "folder-documents"},
{HomePath, "user-home"},
{MusicPath, "folder-music"},
{VideosPath, "folder-videos"},
{DesktopPath, "user-desktop"}
};
inline QString getIconName(const QString &path)
{
if(QFileInfo(path).isDir())
{
if(folderIcon.contains(path))
return folderIcon[path];
else return "folder";
}else
{
QMimeDatabase mime;
auto type = mime.mimeTypeForFile(path);
qDebug()<< type.genericIconName();
return type.iconName();
}
return "text-css";
}
const QString SettingPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)+"/pix/";
const QString CachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)+"/pix/";
const QString NotifyDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
const QString App = "Index";
const QString version = "1.0";
inline QString ucfirst(const QString &str)/*uppercase first letter*/
{
if (str.isEmpty()) return "";
QStringList tokens;
QStringList result;
QString output;
if(str.contains(" "))
{
tokens = str.split(" ");
for(auto str : tokens)
{
str = str.toLower();
str[0] = str[0].toUpper();
result<<str;
}
output = result.join(" ");
}else output = str;
return output.simplified();
}
inline bool fileExists(const QString &url)
{
QFileInfo path(url);
if (path.exists()) return true;
else return false;
}
inline void saveSettings(const QString &key, const QVariant &value, const QString &group)
{
QSettings setting("Babe","babe");
setting.beginGroup(group);
setting.setValue(key,value);
setting.endGroup();
}
inline QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue)
{
QVariant variant;
QSettings setting("Babe","babe");
setting.beginGroup(group);
variant = setting.value(key,defaultValue);
setting.endGroup();
return variant;
}
inline bool isMobile()
{
#if defined(Q_OS_ANDROID)
return true;
#elif defined(Q_OS_LINUX)
return false;
#elif defined(Q_OS_WIN32)
return false;
#elif defined(Q_OS_WIN64)
return false;
#elif defined(Q_OS_MACOS)
return false;
#elif defined(Q_OS_IOS)
return true;
#elif defined(Q_OS_HAIKU)
return false;
#endif
}
}
#endif // INX_H
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickStyle>
#include <QIcon>
#include <QCommandLineParser>
#include <QFileInfo>
#include <index.h>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
Index index;
QQmlApplicationEngine engine;
auto context = engine.rootContext();
context->setContextProperty("inx", &index);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import org.kde.kirigami 2.0 as Kirigami
import "widgets"
import "widgets/views"
import "widgets/sidebar"
import "widgets_templates"
import "Index.js" as INX
Kirigami.ApplicationWindow
{
id: root
visible: true
width: 640
height: 480
title: qsTr("Index")
property int sidebarWidth: Kirigami.Units.gridUnit * 11
pageStack.defaultColumnWidth: sidebarWidth
pageStack.initialPage: [placesSidebar, browser]
pageStack.interactive: isMobile
pageStack.separatorVisible: pageStack.wideMode
readonly property bool isMobile : Kirigami.Settings.isMobile
readonly property int contentMargins: isMobile ? 8 : 10
readonly property int defaultFontSize: Kirigami.Theme.defaultFont.pointSize
readonly property var fontSizes: ({
tiny: defaultFontSize - 2,
small: defaultFontSize -1,
default: defaultFontSize,
big: defaultFontSize + 1,
large: defaultFontSize + 2
})
property string backgroundColor: Kirigami.Theme.backgroundColor
property string textColor: Kirigami.Theme.textColor
property string highlightColor: Kirigami.Theme.highlightColor
property string highlightedTextColor: Kirigami.Theme.highlightedTextColor
property string buttonBackgroundColor: Kirigami.Theme.buttonBackgroundColor
property string viewBackgroundColor: Kirigami.Theme.viewBackgroundColor
property string altColor: Kirigami.Theme.complementaryBackgroundColor
property var iconSizes : ({
small : 16,
medium : 22,
large: 48,
})
property int iconSize : iconSizes.medium
property int rowHeight : 32
overlay.modal: Rectangle {
color: isMobile ? darkColor : "transparent"
opacity: 0.5
height: root.height
}
overlay.modeless: Rectangle {
color: "transparent"
}
header: IndexToolbar
{
id: mainHeader
}
PlacesSidebar
{
id: placesSidebar
anchors.fill: parent
onPlaceClicked: browser.openFolder(path)
}
Browser
{
id: browser
anchors.fill: parent
Component.onCompleted:
{
browser.openFolder(inx.homePath())
}
}
ItemMenu
{
id: itemMenu
onBookmarkClicked: INX.bookmarkFolder(path)
}
}
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>widgets/IndexToolbar.qml</file>
<file>widgets/views/icons/IconsView.qml</file>
<file>widgets_templates/IndexPage.qml</file>
<file>widgets_templates/IndexListDelegate.qml</file>
<file>widgets_templates/IndexList.qml</file>
<file>widgets_templates/IndexIconDelegate.qml</file>
<file>widgets_templates/IndexGrid.qml</file>
<file>widgets_templates/IndexButton.qml</file>
<file>widgets/sidebar/SidebarDelegate.qml</file>
<file>widgets/sidebar/PlacesSidebar.qml</file>
<file>widgets_templates/IndexDelegate.qml</file>
<file>widgets/views/Browser.qml</file>
<file>widgets/views/BrowserFooter.qml</file>
<file>widgets_templates/ItemMenu.qml</file>
<file>Index.js</file>
<file>widgets/views/PathBar.qml</file>
<file>widgets/views/PathBarDelegate.qml</file>
</qresource>
</RCC>
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../widgets_templates"
import "views"
ToolBar
{
position: ToolBar.Header
property alias pathBar : pathBar
property string accentColor : highlightColor
signal searchClicked()
signal menuClicked()
id: pixBar
RowLayout
{
anchors.fill: parent
Item
{
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumWidth: 44
IndexButton
{
anchors.centerIn: parent
iconName: "application-menu"
onClicked: menuClicked()
// iconColor: globalDrawer.visible ? accentColor : textColor
hoverEnabled: !isMobile
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("Menu")
}
}
Item { Layout.fillWidth: true; Layout.maximumWidth: parent.width*0.05 }
PathBar
{
id: pathBar
Layout.fillWidth: true
}
Item { Layout.fillWidth: true; Layout.maximumWidth: parent.width*0.05 }
Item
{
Layout.alignment: Qt.AlignRight
Layout.fillWidth: true
Layout.fillHeight: true
Layout.maximumWidth: 44
IndexButton
{
id: searchView
anchors.centerIn: parent
// iconColor: currentIndex === views.search? accentColor : textColor
iconName: "edit-find"
onClicked: searchClicked()
hoverEnabled: !isMobile
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("Search")
}
}
}
}
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../../widgets_templates"
ColumnLayout
{
property alias placesList : placesList
signal placeClicked (string path)
focus: true
ListView
{
id: placesList
clip: true
Layout.fillHeight: true
Layout.fillWidth: true
keyNavigationEnabled: true
highlight: Rectangle
{
width: placesList.width
height: placesList.currentItem.height
color: highlightColor
}
focus: true
interactive: true
highlightFollowsCurrentItem: true
highlightMoveDuration: 0
snapMode: ListView.SnapToItem
section.property : "type"
section.criteria: ViewSection.FullString
section.delegate: IndexDelegate
{
id: delegate
label: section
isSection: true
boldLabel: true
height: mainHeader.height
}
model: ListModel
{}
delegate: SidebarDelegate
{
id: placeDelegate
Connections
{
target: placeDelegate
onClicked:
{
placesList.currentIndex = index
placeClicked(placesList.model.get(index).path)
}
}
}
}
Component.onCompleted: populate()
function populate()
{
clear()
var places = inx.getDefaultPaths()
places.push(inx.getBookmarks())
places.push(inx.getDevices())
if(places.length > 0)
for(var i in places)
placesList.model.append(places[i])
}
function clear()
{
placesList.model.clear()
}
}
import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import org.kde.kirigami 2.2 as Kirigami
ItemDelegate
{
width: parent.width
height: rowHeight
clip: true
property string labelColor: ListView.isCurrentItem ? highlightedTextColor : textColor
Rectangle
{
anchors.fill: parent
color: index % 2 === 0 ? Qt.darker(backgroundColor) : "transparent"
opacity: 0.05
}
RowLayout
{
anchors.fill: parent
Item
{
Layout.fillHeight: true
width: parent.height
Kirigami.Icon
{
anchors.centerIn: parent
source: iconName? iconName : ""