Refactor the code

This commit is contained in:
cutefishd 2021-03-29 16:51:34 +08:00
parent aa449f52ad
commit c3d7c6eedf
90 changed files with 4047 additions and 10926 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
project(cutefish-filemanager LANGUAGES CXX) project(filemanager LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
@ -8,62 +8,58 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Quick Concurrent DBus LinguistTools REQUIRED) find_package(Qt5 COMPONENTS Core DBus Quick LinguistTools REQUIRED)
find_package(KF5KIO)
find_package(MeuiKit REQUIRED) find_package(MeuiKit REQUIRED)
find_package(KF5KIO)
find_package(KF5Solid)
add_executable(cutefish-filemanager add_executable(cutefish-filemanager
src/main.cpp main.cpp
src/fm.cpp model/foldermodel.cpp
src/fmh.cpp model/placesmodel.cpp
src/fmstatic.cpp model/placesitem.cpp
src/fmlist.cpp model/pathbarmodel.cpp
src/handy.cpp model/dirlister.cpp
src/placeslist.cpp model/positioner.cpp
src/pathlist.cpp
src/baselist.cpp
src/basemodel.cpp
src/rubberband.cpp
src/iconthemeprovider.cpp
src/lib/foldermodel.cpp dialogs/propertiesdialog.cpp
src/lib/positioner.cpp widgets/rubberband.cpp
src/lib/itemviewadapter.cpp widgets/itemviewadapter.cpp
src/lib/fileitemactions.cpp
src/lib/placesmodel.cpp
src/lib/placesitem.cpp
src/dialogs/propertiesdialog.cpp desktop/desktopview.cpp
desktop/desktopsettings.cpp
src/desktop/desktopview.cpp helper/thumbnailer.cpp
src/desktop/desktopsettings.cpp helper/pathhistory.cpp
desktopiconprovider.cpp
qml.qrc qml.qrc
) )
target_link_libraries(cutefish-filemanager
PRIVATE
Qt5::Core
Qt5::DBus
Qt5::Quick
KF5::KIOCore
KF5::KIOFileWidgets
KF5::KIOWidgets
KF5::Solid
MeuiKit
)
file(GLOB TS_FILES translations/*.ts) file(GLOB TS_FILES translations/*.ts)
qt5_create_translation(QM_FILES ${TS_FILES}) qt5_create_translation(QM_FILES ${TS_FILES})
add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES}) add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES})
add_dependencies(${PROJECT_NAME} translations) add_dependencies(cutefish-filemanager translations)
target_link_libraries(cutefish-filemanager install(TARGETS cutefish-filemanager RUNTIME DESTINATION /usr/bin)
PRIVATE
Qt5::Core
Qt5::GuiPrivate
Qt5::Quick
Qt5::Concurrent
Qt5::DBus
KF5::KIOCore
KF5::KIOFileWidgets
KF5::KIOWidgets
MeuiKit
)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION /usr/bin)
install(FILES cutefish-filemanager.desktop DESTINATION "/usr/share/applications") install(FILES cutefish-filemanager.desktop DESTINATION "/usr/share/applications")
install(FILES ${QM_FILES} DESTINATION /usr/share/cutefish-filemanager/translations) install(FILES ${QM_FILES} DESTINATION /usr/share/cutefish-filemanager/translations)

View file

@ -4,6 +4,14 @@ Cutefish File Manager
## Dependencies ## Dependencies
### Ubuntu
```
sudo apt install libkf5solid-dev
```
### ArchLinux
```shell ```shell
sudo pacman -S extra-cmake-modules qt5-base qt5-quickcontrols2 taglib kio sudo pacman -S extra-cmake-modules qt5-base qt5-quickcontrols2 taglib kio
``` ```

View file

@ -1,7 +1,7 @@
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
Name=File Manager Name=File Manager
Name[zh_CN]= Name[zh_CN]=
GenericName=File Manager GenericName=File Manager
Comment=Cutefish File Manager Comment=Cutefish File Manager
Exec=cutefish-filemanager %U Exec=cutefish-filemanager %U

1
debian/control vendored
View file

@ -6,6 +6,7 @@ Build-Depends: cmake,
debhelper (>= 9), debhelper (>= 9),
extra-cmake-modules, extra-cmake-modules,
libkf5kio-dev, libkf5kio-dev,
libkf5solid-dev,
qtbase5-dev, qtbase5-dev,
qtbase5-private-dev, qtbase5-private-dev,
qtdeclarative5-dev, qtdeclarative5-dev,

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "desktopsettings.h" #include "desktopsettings.h"
#include <QDBusServiceWatcher> #include <QDBusServiceWatcher>

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 SETTINGS_H #ifndef SETTINGS_H
#define SETTINGS_H #define SETTINGS_H

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "desktopview.h" #include "desktopview.h"
#include <QQmlEngine> #include <QQmlEngine>
@ -15,7 +34,6 @@ DesktopView::DesktopView(QQuickView *parent)
m_screenRect = qApp->primaryScreen()->geometry(); m_screenRect = qApp->primaryScreen()->geometry();
m_screenAvailableRect = qApp->primaryScreen()->availableGeometry(); m_screenAvailableRect = qApp->primaryScreen()->availableGeometry();
// setFlags(Qt::Window | Qt::FramelessWindowHint);
setTitle(tr("Desktop")); setTitle(tr("Desktop"));
KWindowSystem::setType(winId(), NET::Desktop); KWindowSystem::setType(winId(), NET::Desktop);
@ -25,7 +43,7 @@ DesktopView::DesktopView(QQuickView *parent)
setScreen(qApp->primaryScreen()); setScreen(qApp->primaryScreen());
setResizeMode(QQuickView::SizeRootObjectToView); setResizeMode(QQuickView::SizeRootObjectToView);
setSource(QStringLiteral("qrc:/qml/Desktop/Desktop.qml")); setSource(QStringLiteral("qrc:/qml/Desktop/main.qml"));
onGeometryChanged(); onGeometryChanged();

50
desktop/desktopview.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 DESKTOPVIEW_H
#define DESKTOPVIEW_H
#include <QQuickView>
class DesktopView : public QQuickView
{
Q_OBJECT
Q_PROPERTY(QRect screenRect READ screenRect NOTIFY screenRectChanged)
Q_PROPERTY(QRect screenAvailableRect READ screenAvailableRect NOTIFY screenAvailableGeometryChanged)
public:
explicit DesktopView(QQuickView *parent = nullptr);
QRect screenRect();
QRect screenAvailableRect();
signals:
void screenRectChanged();
void screenAvailableGeometryChanged();
private slots:
void onGeometryChanged();
void onAvailableGeometryChanged(const QRect &geometry);
private:
QRect m_screenRect;
QRect m_screenAvailableRect;
};
#endif // DESKTOPVIEW_H

53
desktopiconprovider.cpp Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "desktopiconprovider.h"
#include <QIcon>
DesktopIconProvider::DesktopIconProvider()
: QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
QPixmap DesktopIconProvider::requestPixmap(const QString &id, QSize *realSize,
const QSize &requestedSize)
{
// Sanitize requested size
QSize size(requestedSize);
if (size.width() < 1)
size.setWidth(1);
if (size.height() < 1)
size.setHeight(1);
// Return real size
if (realSize)
*realSize = size;
// Is it a path?
if (id.startsWith(QLatin1Char('/')))
return QPixmap(id).scaled(size);
// Return icon from theme or fallback to a generic icon
QIcon icon = QIcon::fromTheme(id);
if (icon.isNull())
icon = QIcon::fromTheme(QLatin1String("application-x-desktop"));
return icon.pixmap(size);
}

33
desktopiconprovider.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 DESKTOPICONPROVIDER_H
#define DESKTOPICONPROVIDER_H
#include <QtQuick/QQuickImageProvider>
class DesktopIconProvider : public QQuickImageProvider
{
public:
DesktopIconProvider();
QPixmap requestPixmap(const QString &id, QSize *realSize, const QSize &requestedSize);
};
#endif // DESKTOPICONPROVIDER_H

View file

@ -1,5 +1,27 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "propertiesdialog.h" #include "propertiesdialog.h"
#include "../iconthemeprovider.h" #include "../desktopiconprovider.h"
#include <KFileItemListProperties>
#include <KIO/CopyJob>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@ -9,6 +31,19 @@
#include <QQmlContext> #include <QQmlContext>
#include <QDebug> #include <QDebug>
inline QString concatPaths(const QString &path1, const QString &path2)
{
Q_ASSERT(!path2.startsWith(QLatin1Char('/')));
if (path1.isEmpty()) {
return path2;
} else if (!path1.endsWith(QLatin1Char('/'))) {
return path1 + QLatin1Char('/') + path2;
} else {
return path1 + path2;
}
}
PropertiesDialog::PropertiesDialog(const KFileItem &item, QObject *parent) PropertiesDialog::PropertiesDialog(const KFileItem &item, QObject *parent)
: QObject(parent) : QObject(parent)
{ {
@ -40,7 +75,7 @@ void PropertiesDialog::showDialog(const KFileItem &item)
{ {
PropertiesDialog *dlg = new PropertiesDialog(item); PropertiesDialog *dlg = new PropertiesDialog(item);
QQmlApplicationEngine *engine = new QQmlApplicationEngine; QQmlApplicationEngine *engine = new QQmlApplicationEngine;
engine->addImageProvider(QStringLiteral("icontheme"), new IconThemeProvider()); engine->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider());
engine->rootContext()->setContextProperty("main", dlg); engine->rootContext()->setContextProperty("main", dlg);
engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml")); engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml"));
} }
@ -49,7 +84,7 @@ void PropertiesDialog::showDialog(const KFileItemList &items)
{ {
PropertiesDialog *dlg = new PropertiesDialog(items); PropertiesDialog *dlg = new PropertiesDialog(items);
QQmlApplicationEngine *engine = new QQmlApplicationEngine; QQmlApplicationEngine *engine = new QQmlApplicationEngine;
engine->addImageProvider(QStringLiteral("icontheme"), new IconThemeProvider()); engine->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider());
engine->rootContext()->setContextProperty("main", dlg); engine->rootContext()->setContextProperty("main", dlg);
engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml")); engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml"));
} }
@ -59,6 +94,11 @@ bool PropertiesDialog::multiple() const
return m_multiple; return m_multiple;
} }
bool PropertiesDialog::isWritable() const
{
return m_items.first().isWritable();
}
QString PropertiesDialog::location() const QString PropertiesDialog::location() const
{ {
return m_location; return m_location;
@ -99,6 +139,46 @@ QString PropertiesDialog::accessedTime() const
return m_accessedTime; return m_accessedTime;
} }
KFileItemList PropertiesDialog::items() const
{
return m_items;
}
void PropertiesDialog::accept(const QString &text)
{
KFileItemList list = items();
if (list.size() == 1) {
KFileItem item = list.first();
QString n = text;
while (!n.isEmpty() && n[n.length() - 1].isSpace())
n.chop(1);
if (n.isEmpty())
return;
QString newFileName = KIO::encodeFileName(n);
if (fileName() != newFileName) {
QUrl newUrl;
if (!location().isEmpty()) {
newUrl = location();
newUrl.setPath(concatPaths(newUrl.path(), newFileName));
newUrl.setScheme(item.url().scheme());
auto job = KIO::move(item.url(), newUrl, KIO::HideProgressInfo);
job->start();
}
}
}
}
void PropertiesDialog::reject()
{
}
void PropertiesDialog::init() void PropertiesDialog::init()
{ {
m_multiple = m_items.count() > 1; m_multiple = m_items.count() > 1;
@ -122,13 +202,11 @@ void PropertiesDialog::init()
m_size = KIO::convertSize(m_items.first().size()); m_size = KIO::convertSize(m_items.first().size());
m_location = QFileInfo(m_items.first().localPath()).dir().path(); m_location = QFileInfo(m_items.first().localPath()).dir().path();
qDebug() << m_items.first().mimetype() << " ???";
m_creationTime = item.time(KFileItem::CreationTime).toString(); m_creationTime = item.time(KFileItem::CreationTime).toString();
m_modifiedTime = item.time(KFileItem::ModificationTime).toString(); m_modifiedTime = item.time(KFileItem::ModificationTime).toString();
m_accessedTime = item.time(KFileItem::AccessTime).toString(); m_accessedTime = item.time(KFileItem::AccessTime).toString();
} else { } else {
m_fileName = QString("%1 files").arg(m_items.count()); m_fileName = tr("%1 files").arg(m_items.count());
m_location = QFileInfo(m_items.first().localPath()).dir().path(); m_location = QFileInfo(m_items.first().localPath()).dir().path();
} }
} }

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 PROPERTIESDIALOG_H #ifndef PROPERTIESDIALOG_H
#define PROPERTIESDIALOG_H #define PROPERTIESDIALOG_H
@ -19,6 +38,7 @@ class PropertiesDialog : public QObject
Q_PROPERTY(QString modifiedTime READ modifiedTime CONSTANT) Q_PROPERTY(QString modifiedTime READ modifiedTime CONSTANT)
Q_PROPERTY(QString accessedTime READ accessedTime CONSTANT) Q_PROPERTY(QString accessedTime READ accessedTime CONSTANT)
Q_PROPERTY(bool multiple READ multiple CONSTANT) Q_PROPERTY(bool multiple READ multiple CONSTANT)
Q_PROPERTY(bool isWritable READ isWritable CONSTANT)
public: public:
explicit PropertiesDialog(const KFileItem &item, QObject *parent = nullptr); explicit PropertiesDialog(const KFileItem &item, QObject *parent = nullptr);
@ -30,6 +50,7 @@ public:
static void showDialog(const KFileItemList &items); static void showDialog(const KFileItemList &items);
bool multiple() const; bool multiple() const;
bool isWritable() const;
QString location() const; QString location() const;
QString fileName() const; QString fileName() const;
@ -41,6 +62,11 @@ public:
QString modifiedTime() const; QString modifiedTime() const;
QString accessedTime() const; QString accessedTime() const;
KFileItemList items() const;
Q_INVOKABLE void accept(const QString &text);
Q_INVOKABLE void reject();
signals: signals:
void fileNameChanged(); void fileNameChanged();
void iconNameChanged(); void iconNameChanged();

34
helper/pathhistory.cpp Normal file
View file

@ -0,0 +1,34 @@
#include "pathhistory.h"
#include <QUrl>
PathHistory::PathHistory(QObject *parent)
: QObject(parent)
{
}
void PathHistory::append(const QUrl &path)
{
m_prevHistory.append(path);
}
QUrl PathHistory::posteriorPath()
{
if (m_postHistory.isEmpty())
return QUrl();
return m_postHistory.takeLast();
}
QUrl PathHistory::previousPath()
{
if (m_prevHistory.isEmpty())
return QUrl();
if (m_prevHistory.length() < 2)
return m_prevHistory.at(0);
m_postHistory.append(m_prevHistory.takeLast());
return m_prevHistory.takeLast();
}

23
helper/pathhistory.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef PATHHISTORY_H
#define PATHHISTORY_H
#include <QObject>
class PathHistory : public QObject
{
Q_OBJECT
public:
explicit PathHistory(QObject *parent = nullptr);
void append(const QUrl &path);
QUrl posteriorPath();
QUrl previousPath();
private:
QVector<QUrl> m_prevHistory;
QVector<QUrl> m_postHistory;
};
#endif // PATHHISTORY_H

37
helper/thumbnailer.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "thumbnailer.h"
#include <KIO/PreviewJob>
#include <QDebug>
#include <QImage>
QQuickImageResponse *Thumbnailer::requestImageResponse(const QString &id, const QSize &requestedSize)
{
AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize);
return response;
}
AsyncImageResponse::AsyncImageResponse(const QString &id, const QSize &requestedSize)
: m_id(id)
, m_requestedSize(requestedSize)
{
QStringList plugins = KIO::PreviewJob::defaultPlugins();
auto job = new KIO::PreviewJob(KFileItemList() << KFileItem(QUrl::fromUserInput(id)), requestedSize, &plugins);
connect(job, &KIO::PreviewJob::gotPreview, [this](KFileItem, QPixmap pixmap) {
m_image = pixmap.toImage();
emit this->finished();
});
connect(job, &KIO::PreviewJob::failed, [this](KFileItem) {
emit this->cancel();
emit this->finished();
});
job->start();
}
QQuickTextureFactory *AsyncImageResponse::textureFactory() const
{
return QQuickTextureFactory::textureFactoryForImage(m_image);
}

25
helper/thumbnailer.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef THUMBNAILER_H
#define THUMBNAILER_H
#include <QObject>
#include <QQuickImageProvider>
class AsyncImageResponse : public QQuickImageResponse
{
public:
AsyncImageResponse(const QString &id, const QSize &requestedSize);
QQuickTextureFactory *textureFactory() const override;
private:
QString m_id;
QSize m_requestedSize;
QImage m_image;
};
class Thumbnailer : public QQuickAsyncImageProvider
{
public:
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
};
#endif // THUMBNAILER_H

View file

@ -1,6 +1,120 @@
<svg width="22" height="22" version="1.1" xmlns="http://www.w3.org/2000/svg"> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<defs> <svg
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color:#363636; }</style> xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="22"
height="22"
version="1.1"
id="svg7"
sodipodi:docname="folder-document.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata11">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2160"
inkscape:window-height="1304"
id="namedview9"
showgrid="false"
inkscape:zoom="47.24759"
inkscape:cx="13.724761"
inkscape:cy="13.430708"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g12-3"
inkscape:document-rotation="0" />
<defs
id="defs3">
<style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style>
</defs> </defs>
<path class="ColorScheme-Text" d="m10 3c-1.108 0-2 0.892-2 2v1h-2c-1.108 0-2 0.892-2 2v9c0 1.108 0.892 2 2 2h6c1.108 0 2-0.892 2-2v-1h2c1.108 0 2-0.892 2-2v-6l-5-5h-1zm0 1h2v5h5v5c0 0.554-0.446 1-1 1h-2v-4l-5-5v-1c0-0.1385 0.027656-0.27091 0.078125-0.39062 0.15141-0.35916 0.50638-0.60938 0.92188-0.60938zm3 0.41406 3.5859 3.5859h-3.5859zm-7 2.5859h2v5h5v5c0 0.554-0.446 1-1 1h-6c-0.554 0-1-0.446-1-1v-9c0-0.1385 0.027656-0.27091 0.078125-0.39062 0.15141-0.35916 0.50638-0.60938 0.92188-0.60938zm3 0.41406 3.5859 3.5859h-3.5859z" fill="currentColor"/> <g
id="g12-3"
transform="matrix(0.03076923,0,0,0.03076923,3.1230769,3.1230769)"
style="fill:#363636;fill-opacity:1">
<path
d="M 446.605,124.392 326.608,4.395 C 323.807,1.593 319.984,0 316,0 H 106 C 81.187,0 61,20.187 61,45 v 422 c 0,24.813 20.187,45 45,45 h 300 c 24.813,0 45,-20.187 45,-45 V 135 c 0,-4.09 -1.717,-7.931 -4.395,-10.608 z M 331,51.213 399.787,120 H 346 c -8.271,0 -15,-6.729 -15,-15 z M 406,482 H 106 c -8.271,0 -15,-6.729 -15,-15 V 45 c 0,-8.271 6.729,-15 15,-15 h 195 v 75 c 0,24.813 20.187,45 45,45 h 75 v 317 c 0,8.271 -6.729,15 -15,15 z"
id="path2-6"
style="fill:#363636;fill-opacity:1" />
<path
d="M 346,272 H 166 c -8.284,0 -15,6.716 -15,15 0,8.284 6.716,15 15,15 h 180 c 8.284,0 15,-6.716 15,-15 0,-8.284 -6.716,-15 -15,-15 z"
id="path6"
style="fill:#363636;fill-opacity:1" />
<path
d="M 346,332 H 166 c -8.284,0 -15,6.716 -15,15 0,8.284 6.716,15 15,15 h 180 c 8.284,0 15,-6.716 15,-15 0,-8.284 -6.716,-15 -15,-15 z"
id="path8-7"
style="fill:#363636;fill-opacity:1" />
<path
d="M 286,392 H 166 c -8.284,0 -15,6.716 -15,15 0,8.284 6.716,15 15,15 h 120 c 8.284,0 15,-6.716 15,-15 0,-8.284 -6.716,-15 -15,-15 z"
id="path10"
style="fill:#363636;fill-opacity:1" />
</g>
<g
id="g32"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g34"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g36"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g38"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g40"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g42"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g44"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g46"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g48"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g50"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g52"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g54"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g56"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g58"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
<g
id="g60"
transform="matrix(0.02922392,0,0,0.02922392,3.5186765,3.5186765)" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 751 B

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2021 CutefishOS Team. * Copyright (C) 2021 CutefishOS Team.
* *
* Author: rekols <revenmartin@gmail.com> * Author: revenmartin <revenmartin@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,33 +18,23 @@
*/ */
#include <QApplication> #include <QApplication>
#include <QCommandLineParser>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QTranslator> #include <QTranslator>
#include <QLocale> #include <QLocale>
#include <QAction>
#include <QCommandLineParser>
#include "fmlist.h"
#include "fm.h"
#include "basemodel.h"
#include "baselist.h"
#include "handy.h"
#include "placeslist.h"
#include "pathlist.h"
#include "model/placesmodel.h"
#include "model/foldermodel.h"
#include "model/pathbarmodel.h"
#include "widgets/rubberband.h"
#include "widgets/itemviewadapter.h"
#include "desktop/desktopsettings.h" #include "desktop/desktopsettings.h"
#include "desktop/desktopview.h" #include "desktop/desktopview.h"
#include "rubberband.h" #include "helper/thumbnailer.h"
#include "lib/foldermodel.h"
#include "lib/placesmodel.h"
#include "lib/itemviewadapter.h"
#include "lib/positioner.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const char *uri = "Cutefish.FileManager";
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv); QApplication app(argc, argv);
@ -62,6 +52,16 @@ int main(int argc, char *argv[])
} }
} }
// Register QML Type.
const char *uri = "Cutefish.FileManager";
qmlRegisterType<PlacesModel>(uri, 1, 0, "PlacesModel");
qmlRegisterType<FolderModel>(uri, 1, 0, "FolderModel");
qmlRegisterType<PathBarModel>(uri, 1, 0, "PathBarModel");
qmlRegisterType<RubberBand>(uri, 1, 0, "RubberBand");
qmlRegisterType<ItemViewAdapter>(uri, 1, 0, "ItemViewAdapter");
qmlRegisterType<DesktopSettings>(uri, 1, 0, "DesktopSettings");
qmlRegisterAnonymousType<QAction>(uri, 1);
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("File Manager")); parser.setApplicationDescription(QStringLiteral("File Manager"));
parser.addHelpOption(); parser.addHelpOption();
@ -70,16 +70,6 @@ int main(int argc, char *argv[])
parser.addOption(desktopOption); parser.addOption(desktopOption);
parser.process(app); parser.process(app);
qmlRegisterAnonymousType<QAction>(uri, 1);
qmlRegisterType<DesktopSettings>(uri, 1, 0, "DesktopSettings");
qmlRegisterType<RubberBand>(uri, 1, 0, "RubberBand");
qmlRegisterType<FolderModel>(uri, 1, 0, "FolderModel");
qmlRegisterType<ItemViewAdapter>(uri, 1, 0, "ItemViewAdapter");
qmlRegisterType<Positioner>(uri, 1, 0, "Positioner");
qmlRegisterType<PlacesModel>(uri, 1, 0, "PlacesModel");
if (parser.isSet(desktopOption)) { if (parser.isSet(desktopOption)) {
DesktopView view; DesktopView view;
view.show(); view.show();
@ -87,24 +77,6 @@ int main(int argc, char *argv[])
return app.exec(); return app.exec();
} }
qmlRegisterAnonymousType<BaseList>(uri, 1); // ABSTRACT BASE LIST
qmlRegisterType<BaseModel>(uri, 1, 0, "BaseModel"); // BASE MODEL
qmlRegisterType<PlacesList>(uri, 1, 0, "PlacesList");
qmlRegisterType<PathList>(uri, 1, 0, "PathList");
qmlRegisterType<FMList>(uri, 1, 0, "FMList");
qmlRegisterSingletonType<FMStatic>(uri, 1, 0, "FM", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return new FMStatic;
});
qmlRegisterSingletonType<Handy>(uri, 1, 0, "Handy", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return new Handy;
});
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/qml/main.qml")); const QUrl url(QStringLiteral("qrc:/qml/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
@ -113,6 +85,7 @@ int main(int argc, char *argv[])
QCoreApplication::exit(-1); QCoreApplication::exit(-1);
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
engine.load(url); engine.load(url);
engine.addImageProvider("thumbnailer", new Thumbnailer());
return app.exec(); return app.exec();
} }

39
model/dirlister.cpp Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "dirlister.h"
DirLister::DirLister(QObject *parent)
: KDirLister(parent)
{
}
DirLister::~DirLister()
{
}
void DirLister::handleError(KIO::Job *job)
{
if (!autoErrorHandlingEnabled()) {
emit error(job->errorString());
return;
}
KDirLister::handleError(job);
}

41
model/dirlister.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 DIRLISTER_H
#define DIRLISTER_H
#include <KDirLister>
#include <KIO/Job>
class DirLister : public KDirLister
{
Q_OBJECT
public:
explicit DirLister(QObject *parent = nullptr);
~DirLister() override;
Q_SIGNALS:
void error(const QString &string);
protected:
void handleError(KIO::Job *job) override;
};
#endif // DIRLISTER_H

1126
model/foldermodel.cpp Normal file

File diff suppressed because it is too large Load diff

202
model/foldermodel.h Normal file
View file

@ -0,0 +1,202 @@
#ifndef FOLDERMODEL_H
#define FOLDERMODEL_H
#include "../widgets/itemviewadapter.h"
#include "../helper/pathhistory.h"
#include <QSortFilterProxyModel>
#include <QItemSelectionModel>
#include <QQmlParserStatus>
#include <QQuickItem>
#include <KDirLister>
#include <KDirModel>
#include <KDirWatch>
#include <KActionCollection>
class QDrag;
class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged)
Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
Q_PROPERTY(QObject *viewAdapter READ viewAdapter WRITE setViewAdapter NOTIFY viewAdapterChanged)
Q_PROPERTY(QString statusText READ statusText NOTIFY statusTextChanged)
public:
enum DataRole {
BlankRole = Qt::UserRole + 1,
SelectedRole,
IsDirRole,
UrlRole,
FileNameRole,
IconNameRole,
ThumbnailRole
};
enum FilterMode {
NoFilter = 0,
FilterShowMatches,
FilterHideMatches,
};
enum Status {
None,
Ready,
Listing,
Canceled,
};
Q_ENUM(Status)
struct DragImage {
int row;
QRect rect;
QPoint cursorOffset;
QImage image;
bool blank;
};
explicit FolderModel(QObject *parent = nullptr);
~FolderModel() override;
void classBegin() override;
void componentComplete() override;
QHash<int, QByteArray> roleNames() const override;
static QHash<int, QByteArray> staticRoleNames();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
KFileItem itemForIndex(const QModelIndex &index) const;
QList<QUrl> selectedUrls() const;
QString url() const;
void setUrl(const QString &url);
QUrl resolvedUrl() const;
Q_INVOKABLE QUrl resolve(const QString &url);
Status status() const;
void setStatus(Status status);
int sortMode() const;
void setSortMode(int mode);
bool sortDirsFirst() const;
void setSortDirsFirst(bool enable);
QObject *viewAdapter() const;
void setViewAdapter(QObject *adapter);
bool dragging() const;
bool isDir(const QModelIndex &index, const KDirModel *dirModel) const;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
Qt::DropActions supportedDragActions() const override;
Qt::DropActions supportedDropActions() const override;
KFileItem rootItem() const;
QString statusText();
Q_INVOKABLE QString homePath() const;
Q_INVOKABLE QString desktopPath() const;
Q_INVOKABLE QAction *action(const QString &name) const;
Q_INVOKABLE void up();
Q_INVOKABLE void goBack();
Q_INVOKABLE void goForward();
Q_INVOKABLE bool supportSetAsWallpaper(const QString &mimeType);
Q_INVOKABLE int fileExtensionBoundary(int row);
Q_INVOKABLE bool hasSelection() const;
Q_INVOKABLE bool isSelected(int row) const;
Q_INVOKABLE bool isBlank(int row) const;
Q_INVOKABLE void setSelected(int row);
Q_INVOKABLE void selectAll();
Q_INVOKABLE void toggleSelected(int row);
Q_INVOKABLE void setRangeSelected(int anchor, int to);
Q_INVOKABLE void updateSelection(const QVariantList &rows, bool toggle);
Q_INVOKABLE void clearSelection();
Q_INVOKABLE void pinSelection();
Q_INVOKABLE void unpinSelection();
Q_INVOKABLE void rename(int row, const QString &name);
Q_INVOKABLE void copy();
Q_INVOKABLE void paste();
Q_INVOKABLE void cut();
Q_INVOKABLE void openSelected();
Q_INVOKABLE void deleteSelected();
Q_INVOKABLE void moveSelectedToTrash();
Q_INVOKABLE void emptyTrash();
Q_INVOKABLE void setDragHotSpotScrollOffset(int x, int y);
Q_INVOKABLE void addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image);
Q_INVOKABLE void clearDragImages();
Q_INVOKABLE void dragSelected(int x, int y);
Q_INVOKABLE void setWallpaperSelected();
Q_INVOKABLE void openContextMenu(QQuickItem *visualParent = nullptr, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
Q_INVOKABLE void openPropertiesDialog();
Q_INVOKABLE void openInTerminal();
signals:
void urlChanged();
void resolvedUrlChanged();
void statusChanged();
void sortModeChanged();
void sortDescChanged();
void sortDirsFirstChanged();
void requestRename();
void draggingChanged();
void viewAdapterChanged();
void statusTextChanged();
private slots:
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void dragSelectedInternal(int x, int y);
private:
void invalidateIfComplete();
void invalidateFilterIfComplete();
void createActions();
void updateActions();
void addDragImage(QDrag *drag, int x, int y);
bool isSupportThumbnails(const QString &mimeType) const;
private:
KDirModel *m_dirModel;
KDirWatch *m_dirWatch;
QItemSelectionModel *m_selectionModel;
QItemSelection m_pinnedSelection;
QString m_url;
Status m_status;
int m_sortMode;
bool m_sortDesc;
bool m_sortDirsFirst;
bool m_complete;
KActionCollection m_actionCollection;
QHash<int, DragImage *> m_dragImages;
QModelIndexList m_dragIndexes;
QPoint m_dragHotSpotScrollOffset;
bool m_dragInProgress;
QPointer<ItemViewAdapter> m_viewAdapter;
// Save path history
PathHistory m_pathHistory;
};
#endif // FOLDERMODEL_H

139
model/pathbarmodel.cpp Normal file
View file

@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "pathbarmodel.h"
PathBarModel::PathBarModel(QObject *parent)
: QAbstractItemModel(parent)
{
}
PathBarModel::~PathBarModel()
{
}
QString PathBarModel::url() const
{
return m_url;
}
#include<QDebug>
void PathBarModel::setUrl(const QString &url)
{
if (m_url != url) {
beginResetModel();
m_url = url;
qDeleteAll(m_pathList);
m_pathList.clear();
QString _url = url;
while (_url.endsWith("/"))
_url.chop(1);
_url += '/';
int count = _url.count("/");
for (int i = 0; i < count; ++i) {
_url = QString(_url).left(_url.lastIndexOf("/"));
QString label = QString(_url).right(_url.length() - _url.lastIndexOf("/") - 1);
if (label.isEmpty())
continue;
PathBarItem *item = new PathBarItem;
if (label.contains(":") && i == count - 1) {
item->name = "/";
item->url = QUrl(_url + "///");
} else {
item->name = label;
item->url = QUrl(_url);
}
m_pathList.append(item);
}
std::reverse(m_pathList.begin(), m_pathList.end());
endResetModel();
emit urlChanged();
}
}
QHash<int, QByteArray> PathBarModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[PathBarModel::NameRole] = "name";
roleNames[PathBarModel::UrlRole] = "url";
roleNames[PathBarModel::PathRole] = "path";
return roleNames;
}
int PathBarModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_pathList.size();
}
int PathBarModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 1;
}
QVariant PathBarModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
PathBarItem *item = m_pathList.at(index.row());
switch (role) {
case PathBarModel::NameRole:
return item->name;
case PathBarModel::UrlRole:
return item->url;
case PathBarModel::PathRole:
return item->url.toString(QUrl::PreferLocalFile);
}
return QVariant();
}
QModelIndex PathBarModel::index(int row, int column, const QModelIndex &parent) const
{
if (row < 0 || column != 0 || row >= m_pathList.size()) {
return QModelIndex();
}
if (parent.isValid()) {
return QModelIndex();
}
return createIndex(row, column, m_pathList.at(row));
}
QModelIndex PathBarModel::parent(const QModelIndex &child) const
{
Q_UNUSED(child);
return QModelIndex();
}

67
model/pathbarmodel.h Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 PATHBARMODEL_H
#define PATHBARMODEL_H
#include <QAbstractItemModel>
#include <QUrl>
struct PathBarItem {
QString name;
QUrl url;
};
class PathBarModel : public QAbstractItemModel
{
Q_OBJECT
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
public:
enum DataRole {
NameRole = Qt::UserRole + 1,
UrlRole,
PathRole
};
Q_ENUMS(DataRole);
explicit PathBarModel(QObject *parent = nullptr);
~PathBarModel();
QString url() const;
void setUrl(const QString &url);
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
signals:
void urlChanged();
private:
QString m_url;
QList<PathBarItem *> m_pathList;
};
#endif // PATHBARMODEL_H

View file

@ -1,13 +1,30 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "placesitem.h" #include "placesitem.h"
#include <QDebug> #include <QDebug>
PlacesItem::PlacesItem(const QString &displayName, PlacesItem::PlacesItem(const QString &displayName,
const QString &iconName,
QUrl url, QUrl url,
QObject *parent) QObject *parent)
: QObject(parent) : QObject(parent)
, m_displayName(displayName) , m_displayName(displayName)
, m_iconName(iconName)
, m_url(url) , m_url(url)
{ {
} }
@ -54,5 +71,5 @@ void PlacesItem::setUrl(const QUrl &url)
QString PlacesItem::path() const QString PlacesItem::path() const
{ {
return m_url.toString(); return m_url.toString(QUrl::PreferLocalFile);
} }

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 PLACESITEM_H #ifndef PLACESITEM_H
#define PLACESITEM_H #define PLACESITEM_H
@ -10,7 +29,6 @@ class PlacesItem : public QObject
public: public:
explicit PlacesItem(const QString &displayName = QString(), explicit PlacesItem(const QString &displayName = QString(),
const QString &iconName = QString(),
QUrl url = QUrl(), QUrl url = QUrl(),
QObject *parent = nullptr); QObject *parent = nullptr);

View file

@ -1,63 +1,111 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "placesmodel.h" #include "placesmodel.h"
#include <QStandardPaths> #include <QStandardPaths>
#include <QDir> #include <QDir>
#include <QDebug>
#include <Solid/Device>
#include <Solid/DeviceNotifier>
#include <Solid/StorageDrive>
#include <Solid/StorageAccess>
#include <Solid/Predicate>
PlacesModel::PlacesModel(QObject *parent) PlacesModel::PlacesModel(QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
{ {
const QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); const QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
if (QDir(homePath).exists()) { if (QDir(homePath).exists()) {
PlacesItem *item = new PlacesItem(tr("Home"), "", QUrl::fromLocalFile(homePath)); PlacesItem *item = new PlacesItem(tr("Home"), QUrl::fromLocalFile(homePath));
item->setIconPath("qrc:/images/folder-home.svg"); item->setIconPath("qrc:/images/folder-home.svg");
m_items.append(item); m_items.append(item);
} }
const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
if (QDir(desktopPath).exists()) { if (QDir(desktopPath).exists()) {
PlacesItem *item = new PlacesItem(tr("Desktop"), "", QUrl::fromLocalFile(desktopPath)); PlacesItem *item = new PlacesItem(tr("Desktop"), QUrl::fromLocalFile(desktopPath));
item->setIconPath("qrc:/images/folder-desktop.svg"); item->setIconPath("qrc:/images/folder-desktop.svg");
m_items.append(item); m_items.append(item);
} }
const QString documentsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); const QString documentsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
if (QDir(documentsPath).exists()) { if (QDir(documentsPath).exists()) {
PlacesItem *item = new PlacesItem(tr("Documents"), "folder-documents", QUrl::fromLocalFile(documentsPath)); PlacesItem *item = new PlacesItem(tr("Documents"), QUrl::fromLocalFile(documentsPath));
item->setIconPath("qrc:/images/folder-document.svg"); item->setIconPath("qrc:/images/folder-document.svg");
m_items.append(item); m_items.append(item);
} }
const QString downloadPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); const QString downloadPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
if (QDir(downloadPath).exists()) { if (QDir(downloadPath).exists()) {
PlacesItem *item = new PlacesItem(tr("Downloads"), "folder-downloads", QUrl::fromLocalFile(downloadPath)); PlacesItem *item = new PlacesItem(tr("Downloads"), QUrl::fromLocalFile(downloadPath));
item->setIconPath("qrc:/images/folder-download.svg"); item->setIconPath("qrc:/images/folder-download.svg");
m_items.append(item); m_items.append(item);
} }
const QString musicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation); const QString musicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
if (QDir(musicPath).exists()) { if (QDir(musicPath).exists()) {
PlacesItem *item = new PlacesItem(tr("Music"), "folder-music", QUrl::fromLocalFile(musicPath)); PlacesItem *item = new PlacesItem(tr("Music"), QUrl::fromLocalFile(musicPath));
item->setIconPath("qrc:/images/folder-music.svg"); item->setIconPath("qrc:/images/folder-music.svg");
m_items.append(item); m_items.append(item);
} }
const QString picturePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); const QString picturePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (QDir(picturePath).exists()) { if (QDir(picturePath).exists()) {
PlacesItem *item = new PlacesItem(tr("Pictures"), "folder-pictures", QUrl::fromLocalFile(picturePath)); PlacesItem *item = new PlacesItem(tr("Pictures"), QUrl::fromLocalFile(picturePath));
item->setIconPath("qrc:/images/folder-picture.svg"); item->setIconPath("qrc:/images/folder-picture.svg");
m_items.append(item); m_items.append(item);
} }
const QString videoPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); const QString videoPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
if (QDir(videoPath).exists()) { if (QDir(videoPath).exists()) {
PlacesItem *item = new PlacesItem(tr("Videos"), "folder-videos", QUrl::fromLocalFile(videoPath)); PlacesItem *item = new PlacesItem(tr("Videos"), QUrl::fromLocalFile(videoPath));
item->setIconPath("qrc:/images/folder-video.svg"); item->setIconPath("qrc:/images/folder-video.svg");
m_items.append(item); m_items.append(item);
} }
PlacesItem *trashItem = new PlacesItem(tr("Trash"), "", QUrl(QStringLiteral("trash:/"))); PlacesItem *trashItem = new PlacesItem(tr("Trash"), QUrl(QStringLiteral("trash:/")));
trashItem->setIconPath("qrc:/images/user-trash.svg"); trashItem->setIconPath("qrc:/images/user-trash.svg");
m_items.append(trashItem); m_items.append(trashItem);
Solid::Predicate predicate;
QString predicateStr(
QString::fromLatin1("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]"
" OR "
"[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]"
" OR "
"OpticalDisc.availableContent & 'Audio' ]"
" OR "
"StorageAccess.ignored == false ]"));
predicate = Solid::Predicate::fromString(predicateStr);
Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
const QList<Solid::Device> &deviceList = Solid::Device::listFromQuery(predicate);
for (const Solid::Device &device : deviceList) {
qDebug() << device.udi();
PlacesItem *deviceItem = new PlacesItem(device.udi());
m_items.append(deviceItem);
}
} }
PlacesModel::~PlacesModel() PlacesModel::~PlacesModel()

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 PLACESMODEL_H #ifndef PLACESMODEL_H
#define PLACESMODEL_H #define PLACESMODEL_H

View file

@ -23,13 +23,10 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
class FolderModel; class FolderModel;
class QTimer; class QTimer;
class Positioner : public QAbstractItemModel class Positioner : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(FolderModel *folderModel READ folderModel WRITE setFolderModel NOTIFY folderModelChanged) Q_PROPERTY(FolderModel *folderModel READ folderModel WRITE setFolderModel NOTIFY folderModelChanged)
Q_PROPERTY(int perStripe READ perStripe WRITE setPerStripe NOTIFY perStripeChanged) Q_PROPERTY(int perStripe READ perStripe WRITE setPerStripe NOTIFY perStripeChanged)
@ -74,24 +71,13 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
#ifdef BUILD_TESTING signals:
QHash<int, int> proxyToSourceMapping() const
{
return m_proxyToSource;
}
QHash<int, int> sourceToProxyMapping() const
{
return m_sourceToProxy;
}
#endif
Q_SIGNALS:
void enabledChanged() const; void enabledChanged() const;
void folderModelChanged() const; void folderModelChanged() const;
void perStripeChanged() const; void perStripeChanged() const;
void positionsChanged() const; void positionsChanged() const;
private Q_SLOTS: private slots:
void updatePositions(); void updatePositions();
void sourceStatusChanged(); void sourceStatusChanged();
void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles); void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
@ -137,4 +123,4 @@ private:
bool m_beginInsertRowsCalled = false; // used to sync the amount of begin/endInsertRows calls bool m_beginInsertRowsCalled = false; // used to sync the amount of begin/endInsertRows calls
}; };
#endif #endif // POSITIONER_H

31
qml.qrc
View file

@ -1,11 +1,12 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>qml/main.qml</file> <file>qml/main.qml</file>
<file>qml/FolderPage.qml</file>
<file>qml/SideBar.qml</file> <file>qml/SideBar.qml</file>
<file>qml/SidebarItem.qml</file> <file>qml/FolderListItem.qml</file>
<file>qml/Dialogs/PropertiesDialog.qml</file>
<file>qml/FolderListView.qml</file> <file>qml/FolderListView.qml</file>
<file>qml/PathBar.qml</file> <file>qml/Controls/IconButton.qml</file>
<file>qml/FolderListDelegate.qml</file>
<file>images/dark/go-next.svg</file> <file>images/dark/go-next.svg</file>
<file>images/dark/go-previous.svg</file> <file>images/dark/go-previous.svg</file>
<file>images/dark/grid.svg</file> <file>images/dark/grid.svg</file>
@ -14,27 +15,19 @@
<file>images/light/go-previous.svg</file> <file>images/light/go-previous.svg</file>
<file>images/light/grid.svg</file> <file>images/light/grid.svg</file>
<file>images/light/list.svg</file> <file>images/light/list.svg</file>
<file>qml/IconButton.qml</file> <file>images/folder-desktop.svg</file>
<file>images/folder-document.svg</file>
<file>images/folder-download.svg</file> <file>images/folder-download.svg</file>
<file>images/folder-home.svg</file> <file>images/folder-home.svg</file>
<file>images/folder-music.svg</file> <file>images/folder-music.svg</file>
<file>images/folder-picture.svg</file> <file>images/folder-picture.svg</file>
<file>images/folder-video.svg</file> <file>images/folder-video.svg</file>
<file>images/folder-document.svg</file>
<file>qml/GlobalSettings.qml</file>
<file>qml/FolderIconView.qml</file>
<file>qml/FolderIconDelegate.qml</file>
<file>qml/BrowserView.qml</file>
<file>qml/ItemMenu.qml</file>
<file>qml/BrowserMenu.qml</file>
<file>qml/Desktop/DesktopFolderView.qml</file>
<file>qml/Desktop/FolderViewDropArea.qml</file>
<file>qml/Desktop/FolderItemDelegate.qml</file>
<file>qml/Desktop/Desktop.qml</file>
<file>qml/Desktop/FolderTools.js</file>
<file>qml/Dialogs/PropertiesDialog.qml</file>
<file>qml/IconDelegate.qml</file>
<file>images/folder-desktop.svg</file>
<file>images/user-trash.svg</file> <file>images/user-trash.svg</file>
<file>qml/PathBar.qml</file>
<file>qml/Desktop/main.qml</file>
<file>qml/FolderGridView.qml</file>
<file>qml/GlobalSettings.qml</file>
<file>qml/FolderGridItem.qml</file>
<file>qml/Dialogs/CreateFolderDialog.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1,61 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
Menu {
id: control
property FMList currentList
signal emptyTrashClicked()
signal propertiesClicked()
signal selectAllClicked()
MenuItem {
id: newFolderItem
text: qsTr("New Folder")
enabled: currentList.pathType !== FMList.TRASH_PATH
}
MenuSeparator {
visible: newFolderItem.visible && pasteItem.visible
}
MenuItem {
id: pasteItem
text: qsTr("Paste")
onTriggered: paste()
enabled: currentList.pathType !== FMList.TRASH_PATH
}
MenuItem {
text: qsTr("Select All")
onTriggered: control.selectAllClicked()
}
MenuItem {
id: terminal
text: qsTr("Open in Terminal")
}
MenuItem {
id: properties
text: qsTr("Properties")
onTriggered: {
propertiesClicked()
close()
}
}
MenuItem {
id: emptyItem
text: qsTr("Empty Trash")
visible: currentList.pathType === FMList.TRASH_PATH
onTriggered: control.emptyTrashClicked()
}
function show(parent = control, x, y) {
popup(parent, x, y)
}
}

View file

@ -1,107 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
import Cutefish.FileManager 1.0 as FM
Item {
id: control
property alias model: dirModel
property alias url: dirModel.url
property alias currentView: viewLoader.item
signal openPathBar
FM.FolderModel {
id: dirModel
sortDirsFirst: true
parseDesktopFiles: true
url: dirModel.homePath()
previews: true
previewPlugins: []
}
FM.Positioner {
id: positioner
folderModel: dirModel
enabled: true
}
Rectangle {
anchors.fill: parent
anchors.topMargin: 0
anchors.leftMargin: Meui.Theme.smallRadius / 2
anchors.rightMargin: Meui.Theme.smallRadius
anchors.bottomMargin: Meui.Theme.smallRadius
radius: Meui.Theme.smallRadius
color: Meui.Theme.backgroundColor
Label {
anchors.centerIn: parent
text: qsTr("No Files")
font.pointSize: 20
visible: dirModel.status === FM.FolderModel.Ready && currentView.count === 0
}
}
Loader {
id: viewLoader
anchors.fill: parent
anchors.bottomMargin: Meui.Units.largeSpacing
sourceComponent: switch (settings.viewMethod) {
case 0: return listViewBrowser
case 1: return gridViewBrowser
}
}
Component {
id: listViewBrowser
FolderListView {
id: _listViewBrowser
anchors.fill: parent
model: dirModel
leftMargin: Meui.Units.largeSpacing + Meui.Units.smallSpacing
rightMargin: Meui.Units.largeSpacing + Meui.Units.smallSpacing
topMargin: Meui.Units.smallSpacing
bottomMargin: Meui.Units.largeSpacing * 2
delegate: FolderListDelegate {
id: listDelegate
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
height: 48
}
}
}
Component {
id: gridViewBrowser
FolderIconView {
id: _gridViewBrowser
anchors.fill: parent
model: positioner
leftMargin: Meui.Units.largeSpacing
rightMargin: Meui.Units.largeSpacing
delegate: FolderIconDelegate {
id: iconDelegate
height: _gridViewBrowser.cellHeight
width: _gridViewBrowser.cellWidth
}
}
}
Component.onCompleted: {
control.currentView.forceActiveFocus()
}
function openFolder(url) {
dirModel.url = url
}
}

View file

@ -1,114 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import Qt.labs.platform 1.0
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
FolderViewDropArea {
id: root
visible: true
preventStealing: true
property bool containsDrag: false
folderView: folderViewLayer.item
function isDrag(fromX, fromY, toX, toY) {
var length = Math.abs(fromX - toX) + Math.abs(fromY - toY);
return length >= Qt.styleHints.startDragDistance;
}
function isFileDrag(event) {
var taskUrl = event.mimeData.formats.indexOf("text/x-orgkdeplasmataskmanager_taskurl") !== -1;
var arkService = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-service") !== -1;
var arkPath = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-path") !== -1;
return (event.mimeData.hasUrls || taskUrl || (arkService && arkPath));
}
onDragEnter: {
if (!isFileDrag(event))
event.ignore();
// Firefox tabs are regular drags. Since all of our drop handling is asynchronous
// we would accept this drop and have Firefox not spawn a new window. (Bug 337711)
if (event.mimeData.formats.indexOf("application/x-moz-tabbrowser-tab") > -1) {
event.ignore();
}
}
onDragMove: {
}
onDragLeave: {
}
onDrop: {
}
DesktopSettings {
id: settings
}
Loader {
id: backgroundLoader
anchors.fill: parent
sourceComponent: settings.backgroundType === 0 ? wallpaper : background
}
Component {
id: wallpaper
Image {
source: "file://" + settings.wallpaper
sourceSize: Qt.size(width, height)
fillMode: Image.PreserveAspectCrop
clip: true
cache: false
ColorOverlay {
id: dimsWallpaper
anchors.fill: parent
source: parent
color: "#000000"
opacity: Meui.Theme.darkMode && settings.dimsWallpaper ? 0.4 : 0.0
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
}
}
Component {
id: background
Rectangle {
anchors.fill: parent
color: settings.backgroundColor
}
}
Loader {
id: folderViewLayer
anchors.fill: parent
property bool ready: status == Loader.Ready
property Item view: item ? item : null
property QtObject model: item ? item.model : null
focus: true
active: true
asynchronous: false
source: "DesktopFolderView.qml"
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: main
property int index: model.index
property string name: model.blank ? "" : model.display
property bool blank: model.blank
property bool isDir: model.blank ? false : model.isDir
property bool selected: model.blank ? false : model.selected
property Item frame: contentItem
property Item iconArea: icon
property Item labelArea: label
property bool hovered: (main.GridView.view.hoveredItem === main)
property color hoveredColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.1)
property color selectedColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.9)
Accessible.name: name
Accessible.role: Accessible.Canvas
onSelectedChanged: {
if (selected && !blank) {
contentItem.grabToImage(function(result) {
dir.addItemDragImage(positioner.map(index), main.x + contentItem.x, main.y + contentItem.y, contentItem.width, contentItem.height, result.image);
});
}
}
Rectangle {
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
radius: Meui.Theme.bigRadius
color: selected ? selectedColor : main.hovered ? hoveredColor : "transparent"
border.color: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.3)
border.width: main.hovered || selected ? 1 : 0
}
Item {
id: contentItem
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
PlasmaCore.IconItem {
id: icon
z: 2
anchors.top: parent.top
anchors.topMargin: Meui.Units.smallSpacing
anchors.horizontalCenter: parent.horizontalCenter
height: main.height * 0.55
width: height
animated: false
usesPlasmaTheme: false
smooth: true
source: model.blank ? "" : model.decoration
overlays: model.blank ? "" : model.overlays
}
Label {
id: label
z: 2
anchors.top: icon.bottom
anchors.topMargin: Meui.Units.smallSpacing
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width
textFormat: Text.PlainText
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignTop
wrapMode: Text.Wrap
elide: Text.ElideRight
color: "#FFFFFF"
opacity: model.isHidden ? 0.6 : 1
text: model.blank ? "" : model.display
font.italic: model.isLink
}
DropShadow {
anchors.fill: label
z: 1
horizontalOffset: 1
verticalOffset: 1
radius: Math.round(4 * Meui.Units.devicePixelRatio)
samples: radius * 2 + 1
spread: 0.35
color: "black"
opacity: model.isHidden ? 0.4 : 0.5
source: label
visible: !selected
}
}
}

View file

@ -1,43 +0,0 @@
function effectiveNavDirection(flow, layoutDirection, direction) {
if (direction === Qt.LeftArrow) {
if (flow === GridView.FlowLeftToRight) {
if (layoutDirection === Qt.LeftToRight) {
return Qt.LeftArrow;
} else {
return Qt.RightArrow;
}
} else {
if (layoutDirection === Qt.LeftToRight) {
return Qt.UpArrow;
} else {
return Qt.DownArrow;
}
}
} else if (direction === Qt.RightArrow) {
if (flow === GridView.FlowLeftToRight) {
if (layoutDirection === Qt.LeftToRight) {
return Qt.RightArrow;
} else {
return Qt.LeftArrow;
}
} else {
if (layoutDirection === Qt.LeftToRight) {
return Qt.DownArrow;
} else {
return Qt.UpArrow;
}
}
} else if (direction === Qt.UpArrow) {
if (flow === GridView.FlowLeftToRight) {
return Qt.UpArrow;
} else {
return Qt.LeftArrow;
}
} else if (direction === Qt.DownArrow) {
if (flow === GridView.FlowLeftToRight) {
return Qt.DownArrow;
} else {
return Qt.RightArrow
}
}
}

View file

@ -1,53 +0,0 @@
import QtQuick 2.12
import MeuiKit 1.0 as Meui
import org.kde.draganddrop 2.0 as DragDrop
DragDrop.DropArea {
id: dropArea
property Item folderView: null
function handleDragMove(folderView, pos) {
// Trigger autoscroll.
folderView.scrollLeft = (pos.x < (Meui.Units.largeSpacing * 3));
folderView.scrollRight = (pos.x > width - (Meui.Units.largeSpacing * 3));
folderView.scrollUp = (pos.y < (Meui.Units.largeSpacing * 3));
folderView.scrollDown = (pos.y > height - (Meui.Units.largeSpacing * 3));
folderView.handleDragMove(pos.x, pos.y);
}
function handleDragEnd(folderView) {
// Cancel autoscroll.
folderView.scrollLeft = false;
folderView.scrollRight = false;
folderView.scrollUp = false;
folderView.scrollDown = false;
folderView.endDragMove();
}
onDragMove: {
// TODO: We should reject drag moves onto file items that don't accept drops
// (cf. QAbstractItemModel::flags() here, but DeclarativeDropArea currently
// is currently incapable of rejecting drag events.
if (folderView) {
handleDragMove(folderView, mapToItem(folderView, event.x, event.y));
}
}
onDragLeave: {
if (folderView) {
handleDragEnd(folderView);
}
}
onDrop: {
if (folderView) {
handleDragEnd(folderView);
folderView.drop(folderView, event, mapToItem(folderView, event.x, event.y));
}
}
}

111
qml/Desktop/main.qml Normal file
View file

@ -0,0 +1,111 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
import "../"
Item {
id: rootItem
DesktopSettings {
id: settings
}
Loader {
id: backgroundLoader
anchors.fill: parent
sourceComponent: settings.backgroundType === 0 ? wallpaper : background
}
Component {
id: background
Rectangle {
anchors.fill: parent
color: settings.backgroundColor
}
}
Component {
id: wallpaper
Image {
source: "file://" + settings.wallpaper
sourceSize: Qt.size(width, height)
fillMode: Image.PreserveAspectCrop
clip: true
cache: false
ColorOverlay {
id: dimsWallpaper
anchors.fill: parent
source: parent
color: "#000000"
opacity: Meui.Theme.darkMode && settings.dimsWallpaper ? 0.4 : 0.0
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
}
}
FolderGridView {
anchors.fill: parent
cellHeight: 128
cellWidth: 128
model: FolderModel {
id: folderModel
url: desktopPath()
}
leftMargin: desktopView.screenAvailableRect ? desktopView.screenAvailableRect.x : 0
topMargin: desktopView.screenAvailableRect ? desktopView.screenAvailableRect.y : 0
rightMargin: desktopView.screenRect.width - (desktopView.screenAvailableRect.x + desktopView.screenAvailableRect.width)
bottomMargin: desktopView.screenRect.height - (desktopView.screenAvailableRect.y + desktopView.screenAvailableRect.height)
delegate: FolderGridItem {}
}
Component {
id: rubberBandObject
RubberBand {
id: rubberBand
width: 0
height: 0
z: 99999
color: Meui.Theme.highlightColor
function close() {
opacityAnimation.restart()
}
OpacityAnimator {
id: opacityAnimation
target: rubberBand
to: 0
from: 1
duration: 150
easing {
bezierCurve: [0.4, 0.0, 1, 1]
type: Easing.Bezier
}
onFinished: {
rubberBand.visible = false
rubberBand.enabled = false
rubberBand.destroy()
}
}
}
}
}

View file

@ -0,0 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import MeuiKit 1.0 as Meui
Dialog {
id: control
modal: true
x: (parent.width - control.width) / 2
y: (parent.height - control.height) / 2
}

View file

@ -7,7 +7,7 @@ import MeuiKit 1.0 as Meui
Window { Window {
id: control id: control
title: qsTr("Properties") title: qsTr("Properties")
flags: Qt.Dialog | Qt.WindowStaysOnTopHint flags: Qt.Dialog
visible: true visible: true
@ -67,7 +67,7 @@ Window {
focus: true focus: true
Layout.fillWidth: true Layout.fillWidth: true
Keys.onEscapePressed: control.close() Keys.onEscapePressed: control.close()
enabled: !main.multiple enabled: !main.multiple && main.isWritable
} }
} }
@ -83,6 +83,7 @@ Window {
Label { Label {
text: qsTr("Type:") text: qsTr("Type:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
visible: mimeType.visible visible: mimeType.visible
} }
@ -95,6 +96,7 @@ Window {
Label { Label {
text: qsTr("Location:") text: qsTr("Location:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
} }
Label { Label {
@ -105,18 +107,20 @@ Window {
Label { Label {
text: qsTr("Size:") text: qsTr("Size:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
// visible: size.visible // visible: size.visible
} }
Label { Label {
id: size id: size
text: main.size text: main.size ? main.size : qsTr("Calculating...")
// visible: text // visible: text
} }
Label { Label {
text: qsTr("Created:") text: qsTr("Created:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
visible: creationTime.visible visible: creationTime.visible
} }
@ -129,6 +133,7 @@ Window {
Label { Label {
text: qsTr("Modified:") text: qsTr("Modified:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
visible: modifiedTime.visible visible: modifiedTime.visible
} }
@ -141,6 +146,7 @@ Window {
Label { Label {
text: qsTr("Accessed:") text: qsTr("Accessed:")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
color: Meui.Theme.disabledTextColor
visible: accessTime.visible visible: accessTime.visible
} }
@ -162,13 +168,19 @@ Window {
Button { Button {
text: qsTr("Cancel") text: qsTr("Cancel")
Layout.fillWidth: true Layout.fillWidth: true
onClicked: control.close() onClicked: {
control.close()
main.reject()
}
} }
Button { Button {
text: qsTr("OK") text: qsTr("OK")
Layout.fillWidth: true Layout.fillWidth: true
onClicked: control.close() onClicked: {
main.accept(_textField.text)
control.close()
}
flat: true flat: true
} }
} }

102
qml/FolderGridItem.qml Normal file
View file

@ -0,0 +1,102 @@
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
Item {
id: control
width: GridView.view.cellWidth
height: GridView.view.cellHeight
property Item iconArea: _image.visible ? _image : _icon
property Item textArea: _label
property int index: model.index
property bool hovered: GridView.view.hoveredItem === control
property bool selected: model.selected
property bool blank: model.blank
ColumnLayout {
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
spacing: Meui.Units.smallSpacing
Item {
id: _iconItem
Layout.preferredHeight: parent.height * 0.7
Layout.fillWidth: true
Image {
id: _icon
anchors.centerIn: parent
width: parent.height
height: width
sourceSize: Qt.size(width, height)
source: "image://icontheme/" + model.iconName
visible: !_image.visible
}
Image {
id: _image
anchors.fill: parent
anchors.leftMargin: Meui.Units.smallSpacing
anchors.rightMargin: Meui.Units.smallSpacing
fillMode: Image.PreserveAspectCrop
visible: status === Image.Ready
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
sourceSize.width: width
sourceSize.height: height
source: model.thumbnail ? model.thumbnail : ""
asynchronous: true
cache: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Item {
width: _image.width
height: _image.height
Rectangle {
anchors.centerIn: parent
width: Math.min(parent.width, _image.paintedWidth)
height: Math.min(parent.height, _image.paintedHeight)
radius: Meui.Theme.smallRadius
}
}
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredHeight: Math.min(_label.implicitHeight, height)
Rectangle {
anchors.centerIn: parent
width: Math.min(_label.implicitWidth + Meui.Units.largeSpacing, parent.width)
height: Math.min(_label.implicitHeight + Meui.Units.largeSpacing, parent.height)
color: selected ? Meui.Theme.highlightColor : "transparent"
radius: Meui.Theme.smallRadius
}
Label {
id: _label
anchors.fill: parent
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
elide: Qt.ElideRight
wrapMode: Text.Wrap
color: selected ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
text: model.fileName
}
}
}
}

380
qml/FolderGridView.qml Normal file
View file

@ -0,0 +1,380 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
GridView {
id: control
property Item rubberBand: null
property Item hoveredItem: null
property Item pressedItem: null
property int verticalDropHitscanOffset: 0
property int pressX: -1
property int pressY: -1
property int dragX: -1
property int dragY: -1
property bool ctrlPressed: false
property bool shiftPressed: false
property int previouslySelectedItemIndex: -1
property variant cPress: null
property Item editor: null
property int anchorIndex: 0
property var itemSize: 96 + Meui.Units.fontMetrics.height
property var itemWidth: itemSize + Meui.Units.smallSpacing
property var itemHeight: itemSize + Meui.Units.largeSpacing
property variant cachedRectangleSelection: null
property bool scrollLeft: false
property bool scrollRight: false
property bool scrollUp: false
property bool scrollDown: false
signal keyPress(var event)
leftMargin: Meui.Units.smallSpacing
rightMargin: Meui.Units.smallSpacing
highlightMoveDuration: 0
keyNavigationEnabled : true
keyNavigationWraps : true
Keys.onPressed: {
if (event.key === Qt.Key_Control) {
ctrlPressed = true
} else if (event.key === Qt.Key_Shift) {
shiftPressed = true
if (currentIndex != -1)
anchorIndex = currentIndex
}
control.keyPress(event)
}
Keys.onReleased: {
if (event.key === Qt.Key_Control) {
ctrlPressed = false
} else if (event.key === Qt.Key_Shift) {
shiftPressed = false
anchorIndex = 0
}
}
cellHeight: {
// var extraHeight = calcExtraSpacing(itemHeight, control.height - topMargin - bottomMargin)
return itemHeight // + extraHeight
}
cellWidth: {
var extraWidth = calcExtraSpacing(itemWidth, control.width - leftMargin - rightMargin)
return itemWidth + extraWidth
}
clip: true
currentIndex: -1
ScrollBar.vertical: ScrollBar {
bottomPadding: Meui.Theme.mediumRadius
}
onPressXChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
onPressYChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
onCachedRectangleSelectionChanged: {
if (cachedRectangleSelection === null)
return
if (cachedRectangleSelection.length)
control.currentIndex[0]
folderModel.updateSelection(cachedRectangleSelection, control.ctrlPressed)
}
MouseArea {
id: _mouseArea
anchors.fill: parent
propagateComposedEvents: true
preventStealing: true
acceptedButtons: Qt.RightButton | Qt.LeftButton
hoverEnabled: true
enabled: true
z: -1
onDoubleClicked: {
if (mouse.button === Qt.LeftButton && control.pressedItem)
folderModel.openSelected()
}
onPressed: {
control.forceActiveFocus()
// if (mouse.source === Qt.MouseEventSynthesizedByQt) {
// var index = control.indexAt(mouse.x, mouse.y)
// var indexItem = control.itemAtIndex(index)
// if (indexItem && indexItem.iconArea) {
// control.currentIndex = index
// hoveredItem = indexItem
// } else {
// hoveredItem = null
// }
// }
pressX = mouse.x
pressY = mouse.y
if (!hoveredItem || hoveredItem.blank) {
if (!control.ctrlPressed) {
control.currentIndex = -1
previouslySelectedItemIndex = -1
folderModel.clearSelection()
}
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
} else {
pressedItem = hoveredItem
var pos = mapToItem(hoveredItem, mouse.x, mouse.y)
if (control.shiftPressed && control.currentIndex !== -1) {
folderModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
} else {
if (!control.ctrlPressed && !folderModel.isSelected(hoveredItem.index)) {
previouslySelectedItemIndex = -1
folderModel.clearSelection()
}
if (control.ctrlPressed) {
folderModel.toggleSelected(hoveredItem.index)
} else {
folderModel.setSelected(hoveredItem.index)
}
}
control.currentIndex = hoveredItem.index
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
}
}
onPositionChanged: {
control.ctrlPressed = (mouse.modifiers & Qt.ControlModifier)
control.shiftPressed = (mouse.modifiers & Qt.ShiftModifier)
var cPos = mapToItem(control.contentItem, mouse.x, mouse.y)
var item = control.itemAt(cPos.x, cPos.y)
var leftEdge = Math.min(control.contentX, control.originX)
if (!item || item.blank) {
if (control.hoveredItem/* && !root.containsDrag*/) {
control.hoveredItem = null
}
} else {
var fPos = mapToItem(item.iconArea, mouse.x, mouse.y)
if (fPos.x < 0 || fPos.y < 0 || fPos.x > item.iconArea.width || fPos.y > item.iconArea.height) {
control.hoveredItem = null
} else {
control.hoveredItem = item
}
}
// Trigger autoscroll.
if (pressX != -1) {
control.scrollLeft = (mouse.x <= 0 && control.contentX > leftEdge);
control.scrollRight = (mouse.x >= control.width
&& control.contentX < control.contentItem.width - control.width);
control.scrollUp = (mouse.y <= 0 && control.contentY > 0);
control.scrollDown = (mouse.y >= control.height
&& control.contentY < control.contentItem.height - control.height);
}
// Update rubberband geometry.
if (control.rubberBand) {
var rB = control.rubberBand
if (cPos.x < cPress.x) {
rB.x = Math.max(leftEdge, cPos.x)
rB.width = Math.abs(rB.x - cPress.x)
} else {
rB.x = cPress.x
var ceil = Math.max(control.width, control.contentItem.width) + leftEdge
rB.width = Math.min(ceil - rB.x, Math.abs(rB.x - cPos.x))
}
if (cPos.y < cPress.y) {
rB.y = Math.max(0, cPos.y)
rB.height = Math.abs(rB.y - cPress.y)
} else {
rB.y = cPress.y
var ceil = Math.max(control.height, control.contentItem.height)
rB.height = Math.min(ceil - rB.y, Math.abs(rB.y - cPos.y))
}
// Ensure rubberband is at least 1px in size or else it will become
// invisible and not match any items.
rB.width = Math.max(1, rB.width)
rB.height = Math.max(1, rB.height)
control.rectangleSelect(rB.x, rB.y, rB.width, rB.height)
return
}
if (pressX != -1) {
if (pressedItem != null && folderModel.isSelected(pressedItem.index)) {
control.dragX = mouse.x
control.dragY = mouse.y
control.verticalDropHitscanOffset = pressedItem.y + (pressedItem.height / 2)
folderModel.dragSelected(mouse.x, mouse.y)
control.dragX = -1
control.dragY = -1
clearPressState()
} else {
folderModel.pinSelection()
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false
}
}
}
onClicked: {
clearPressState()
if (mouse.button === Qt.RightButton)
return
if (!hoveredItem)
return;
// var pos = mapToItem(hoveredItem, mouse.x, mouse.y);
// if (pos.x < 0 || pos.x > hoveredItem.width || pos.y < 0 || pos.y > hoveredItem.height) {
// hoveredItem = null
// previouslySelectedItemIndex = -1
// folderModel.clearSelection()
// return
// }
}
onReleased: pressCanceled()
onCanceled: pressCanceled()
}
function clearPressState() {
pressedItem = null
pressX = -1
pressY = -1
}
function pressCanceled() {
if (control.rubberBand) {
control.rubberBand.close()
control.rubberBand = null
control.interactive = true
// control.cachedRectangleSelection = null
folderModel.unpinSelection()
}
clearPressState()
}
function rectangleSelect(x, y, width, height) {
var rows = (control.flow === GridView.FlowLeftToRight)
var axis = rows ? control.width : control.height
var step = rows ? cellWidth : cellHeight
var perStripe = Math.floor(axis / step)
var stripes = Math.ceil(control.count / perStripe)
var cWidth = control.cellWidth - (2 * Meui.Units.smallSpacing)
var cHeight = control.cellHeight - (2 * Meui.Units.smallSpacing)
var midWidth = control.cellWidth / 2
var midHeight = control.cellHeight / 2
var indices = []
for (var s = 0; s < stripes; s++) {
for (var i = 0; i < perStripe; i++) {
var index = (s * perStripe) + i
if (index >= control.count) {
break
}
if (folderModel.isBlank(index)) {
continue
}
var itemX = ((rows ? i : s) * control.cellWidth)
var itemY = ((rows ? s : i) * control.cellHeight)
if (control.effectiveLayoutDirection === Qt.RightToLeft) {
itemX -= (rows ? control.contentX : control.originX)
itemX += cWidth
itemX = (rows ? control.width : control.contentItem.width) - itemX
}
// Check if the rubberband intersects this cell first to avoid doing more
// expensive work.
if (control.rubberBand.intersects(Qt.rect(itemX + Meui.Units.smallSpacing, itemY + Meui.Units.smallSpacing,
cWidth, cHeight))) {
var item = control.contentItem.childAt(itemX + midWidth, itemY + midHeight)
// If this is a visible item, check for intersection with the actual
// icon or label rects for better feel.
if (item && item.iconArea) {
var iconRect = Qt.rect(itemX + item.iconArea.x, itemY + item.iconArea.y,
item.iconArea.width, item.iconArea.height)
if (control.rubberBand.intersects(iconRect)) {
indices.push(index)
continue
}
var labelRect = Qt.rect(itemX + item.textArea.x, itemY + item.textArea.y,
item.textArea.width, item.textArea.height)
if (control.rubberBand.intersects(labelRect)) {
indices.push(index)
continue
}
} else {
// Otherwise be content with the cell intersection.
indices.push(index)
}
}
}
}
control.cachedRectangleSelection = indices
}
function calcExtraSpacing(cellSize, containerSize) {
var availableColumns = Math.floor(containerSize / cellSize)
var extraSpacing = 0
if (availableColumns > 0) {
var allColumnSize = availableColumns * cellSize
var extraSpace = Math.max(containerSize - allColumnSize, Meui.Units.smallSpacing)
extraSpacing = extraSpace / availableColumns
}
return Math.floor(extraSpacing)
}
}

View file

@ -1,102 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: main
property int index: model.index
property string name: model.blank ? "" : model.display
property bool blank: model.blank
property bool isDir: model.blank ? false : model.isDir
property bool selected: model.blank ? false : model.selected
property Item frame: contentItem
property Item iconArea: icon
property Item labelArea: label
property bool hovered: (main.GridView.view.hoveredItem === main)
property color hoveredColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.1)
property color selectedColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.9)
Accessible.name: name
Accessible.role: Accessible.Canvas
onSelectedChanged: {
if (selected && !blank) {
contentItem.grabToImage(function(result) {
dirModel.addItemDragImage(positioner.map(index), main.x + contentItem.x, main.y + contentItem.y, contentItem.width, contentItem.height, result.image);
});
}
}
Rectangle {
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
radius: Meui.Theme.bigRadius
color: selected ? selectedColor : main.hovered ? hoveredColor : "transparent"
border.color: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.3)
border.width: main.hovered || selected ? 1 : 0
}
Item {
id: contentItem
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
PlasmaCore.IconItem {
id: icon
z: 2
anchors.top: parent.top
anchors.topMargin: Meui.Units.smallSpacing
anchors.horizontalCenter: parent.horizontalCenter
height: main.height * 0.55
width: height
animated: false
usesPlasmaTheme: false
smooth: true
source: model.blank ? "" : model.decoration
overlays: model.blank ? "" : model.overlays
}
Label {
id: label
z: 2
anchors.top: icon.bottom
anchors.topMargin: Meui.Units.smallSpacing
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width
textFormat: Text.PlainText
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignTop
wrapMode: Text.Wrap
elide: Text.ElideRight
color: selected ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
opacity: model.isHidden ? 0.6 : 1
text: model.blank ? "" : model.display
font.italic: model.isLink
}
}
}

View file

@ -1,381 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import MeuiKit 1.0 as Meui
import Cutefish.FileManager 1.0 as FM
GridView {
id: control
// XXXX
property var iconSize: 130 + Meui.Units.largeSpacing
cellWidth: {
var extraWidth = calcExtraSpacing(iconSize, control.width - leftMargin - rightMargin);
return iconSize + extraWidth;
}
cellHeight: {
var extraHeight = calcExtraSpacing(iconSize, control.height - topMargin - bottomMargin);
return iconSize + extraHeight;
}
ScrollBar.vertical: ScrollBar {}
clip: true
property Item rubberBand: null
property Item hoveredItem: null
property Item pressedItem: null
property int pressX: -1
property int pressY: -1
property int dragX: -1
property int dragY: -1
property variant cPress: null
property bool doubleClickInProgress: false
property int anchorIndex: 0
property bool ctrlPressed: false
property bool shiftPressed: false
property bool overflowing: (visibleArea.heightRatio < 1.0 || visibleArea.widthRatio < 1.0)
property bool scrollLeft: false
property bool scrollRight: false
property bool scrollUp: false
property bool scrollDown: false
property variant cachedRectangleSelection: null
property int previouslySelectedItemIndex: -1
property int verticalDropHitscanOffset: 0
flow: GridView.FlowLeftToRight
currentIndex: -1
onPressXChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY);
}
onPressYChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY);
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
// propagateComposedEvents: true
hoverEnabled: true
z: -1
onPressed: {
control.forceActiveFocus()
if (mouse.source === Qt.MouseEventSynthesizedByQt) {
var index = control.indexAt(mouse.x, mouse.y)
var indexItem = control.itemAtIndex(index)
if (indexItem && indexItem.iconArea) {
control.currentIndex = index
hoveredItem = indexItem
} else {
hoveredItem = null
}
}
pressX = mouse.x
pressY = mouse.y
if (!hoveredItem || hoveredItem.blank) {
if (!control.ctrlPressed) {
control.currentIndex = -1;
previouslySelectedItemIndex = -1;
dirModel.clearSelection();
}
if (mouse.buttons & Qt.RightButton) {
clearPressState()
dirModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
} else {
pressedItem = hoveredItem;
if (control.shiftPressed && control.currentIndex !== -1) {
positioner.setRangeSelected(control.anchorIndex, hoveredItem.index);
} else {
if (!control.ctrlPressed && !dirModel.isSelected(positioner.map(hoveredItem.index))) {
previouslySelectedItemIndex = -1;
dirModel.clearSelection();
}
if (control.ctrlPressed) {
dirModel.toggleSelected(positioner.map(hoveredItem.index));
} else {
dirModel.setSelected(positioner.map(hoveredItem.index));
}
control.currentIndex = hoveredItem.index;
if (mouse.buttons & Qt.RightButton) {
clearPressState();
dirModel.openContextMenu(null, mouse.modifiers);
mouse.accepted = true;
}
}
}
}
onPositionChanged: {
control.ctrlPressed = (mouse.modifiers & Qt.ControlModifier);
control.shiftPressed = (mouse.modifiers & Qt.ShiftModifier);
var cPos = mapToItem(control.contentItem, mouse.x, mouse.y);
var item = control.itemAt(cPos.x, cPos.y);
var leftEdge = Math.min(control.contentX, control.originX);
if (!item || item.blank) {
if (control.hoveredItem && !root.containsDrag) {
control.hoveredItem = null;
}
} else {
var fPos = mapToItem(item, mouse.x, mouse.y);
if (fPos.x < 0 || fPos.y < 0 || fPos.x > item.width || fPos.y > item.height) {
control.hoveredItem = null;
} else {
control.hoveredItem = item
}
}
// Trigger autoscroll.
if (pressX != -1) {
control.scrollLeft = (mouse.x <= 0 && control.contentX > leftEdge);
control.scrollRight = (mouse.x >= control.width
&& control.contentX < control.contentItem.width - control.width);
control.scrollUp = (mouse.y <= 0 && control.contentY > 0);
control.scrollDown = (mouse.y >= control.height
&& control.contentY < control.contentItem.height - control.height);
}
// Update rubberband geometry.
if (control.rubberBand) {
var rB = control.rubberBand;
if (cPos.x < cPress.x) {
rB.x = Math.max(leftEdge, cPos.x);
rB.width = Math.abs(rB.x - cPress.x);
} else {
rB.x = cPress.x;
var ceil = Math.max(control.width, control.contentItem.width) + leftEdge;
rB.width = Math.min(ceil - rB.x, Math.abs(rB.x - cPos.x));
}
if (cPos.y < cPress.y) {
rB.y = Math.max(0, cPos.y);
rB.height = Math.abs(rB.y - cPress.y);
} else {
rB.y = cPress.y;
var ceil = Math.max(control.height, control.contentItem.height);
rB.height = Math.min(ceil - rB.y, Math.abs(rB.y - cPos.y));
}
// Ensure rubberband is at least 1px in size or else it will become
// invisible and not match any items.
rB.width = Math.max(1, rB.width);
rB.height = Math.max(1, rB.height);
control.rectangleSelect(rB.x, rB.y, rB.width, rB.height);
return;
}
// Drag initiation.
if (pressX != -1 /*&& root.isDrag(pressX, pressY, mouse.x, mouse.y)*/) {
if (pressedItem != null && dirModel.isSelected(positioner.map(pressedItem.index))) {
dragX = mouse.x;
dragY = mouse.y;
control.verticalDropHitscanOffset = pressedItem.iconArea.y + (pressedItem.iconArea.height / 2)
dirModel.dragSelected(mouse.x, mouse.y);
dragX = -1;
dragY = -1;
clearPressState();
} else {
dirModel.pinSelection();
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false;
}
}
}
onContainsMouseChanged: {
if (!containsMouse && !control.rubberBand) {
clearPressState();
if (control.hoveredItem) {
control.hoveredItem = null;
}
}
}
onCanceled: pressCanceled()
onReleased: pressCanceled()
}
function calcExtraSpacing(cellSize, containerSize) {
var availableColumns = Math.floor(containerSize / cellSize);
var extraSpacing = 0;
if (availableColumns > 0) {
var allColumnSize = availableColumns * cellSize;
var extraSpace = Math.max(containerSize - allColumnSize, 0);
extraSpacing = extraSpace / availableColumns;
}
return Math.floor(extraSpacing);
}
function clearPressState() {
pressedItem = null;
pressX = -1;
pressY = -1;
}
function rectangleSelect(x, y, width, height) {
var rows = (control.flow === GridView.FlowLeftToRight);
var axis = rows ? control.width : control.height;
var step = rows ? cellWidth : cellHeight;
var perStripe = Math.floor(axis / step);
var stripes = Math.ceil(control.count / perStripe);
var cWidth = control.cellWidth - (2 * Meui.Units.smallSpacing);
var cHeight = control.cellHeight - (2 * Meui.Units.smallSpacing);
var midWidth = control.cellWidth / 2;
var midHeight = control.cellHeight / 2;
var indices = [];
for (var s = 0; s < stripes; s++) {
for (var i = 0; i < perStripe; i++) {
var index = (s * perStripe) + i;
if (index >= control.count) {
break;
}
if (positioner.isBlank(index)) {
continue;
}
var itemX = ((rows ? i : s) * control.cellWidth);
var itemY = ((rows ? s : i) * control.cellHeight);
if (control.effectiveLayoutDirection == Qt.RightToLeft) {
itemX -= (rows ? control.contentX : control.originX);
itemX += cWidth;
itemX = (rows ? control.width : control.contentItem.width) - itemX;
}
// Check if the rubberband intersects this cell first to avoid doing more
// expensive work.
if (control.rubberBand.intersects(Qt.rect(itemX + Meui.Units.smallSpacing, itemY + Meui.Units.smallSpacing,
cWidth, cHeight))) {
var item = control.contentItem.childAt(itemX + midWidth, itemY + midHeight);
// If this is a visible item, check for intersection with the actual
// icon or label rects for better feel.
if (item && item.iconArea) {
var iconRect = Qt.rect(itemX + item.iconArea.x, itemY + item.iconArea.y,
item.iconArea.width, item.iconArea.height);
if (control.rubberBand.intersects(iconRect)) {
indices.push(index);
continue;
}
var labelRect = Qt.rect(itemX + item.labelArea.x, itemY + item.labelArea.y,
item.labelArea.width, item.labelArea.height);
if (control.rubberBand.intersects(labelRect)) {
indices.push(index);
continue;
}
} else {
// Otherwise be content with the cell intersection.
indices.push(index);
}
}
}
}
control.cachedRectangleSelection = indices;
}
onCachedRectangleSelectionChanged: {
if (cachedRectangleSelection == null) {
return;
}
if (cachedRectangleSelection.length) {
// Set current index to start of selection.
// cachedRectangleSelection is pre-sorted.
currentIndex = cachedRectangleSelection[0];
}
dirModel.updateSelection(cachedRectangleSelection.map(positioner.map), control.ctrlPressed);
}
function pressCanceled() {
if (control.rubberBand) {
control.rubberBand.close()
control.rubberBand = null
control.interactive = true;
control.cachedRectangleSelection = null;
dirModel.unpinSelection();
}
clearPressState();
control.cancelAutoscroll();
}
function cancelAutoscroll() {
scrollLeft = false;
scrollRight = false;
scrollUp = false;
scrollDown = false;
}
Component {
id: rubberBandObject
FM.RubberBand {
id: rubberBand
width: 0
height: 0
z: 99999
color: Meui.Theme.highlightColor
function close() {
opacityAnimation.restart()
}
OpacityAnimator {
id: opacityAnimation
target: rubberBand
to: 0
from: 1
duration: 150
easing {
bezierCurve: [0.4, 0.0, 1, 1]
type: Easing.Bezier
}
onFinished: {
rubberBand.visible = false
rubberBand.enabled = false
rubberBand.destroy()
}
}
}
}
}

View file

@ -1,79 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: control
property int index: model.index
property string name: model.blank ? "" : model.display
property bool blank: model.blank
property bool isDir: model.blank ? false : model.isDir
property bool selected: model.blank ? false : model.selected
property Item frame: contentItem
property Item iconArea: iconItem
property Item labelArea: label1
property color hoveredColor: Qt.rgba(Meui.Theme.textColor.r,
Meui.Theme.textColor.g,
Meui.Theme.textColor.b, 0.1)
Accessible.name: name
Accessible.role: Accessible.Canvas
MouseArea {
id: _mouseArea
anchors.fill: parent
hoverEnabled: true
}
Rectangle {
z: -1
anchors.fill: parent
radius: Meui.Theme.bigRadius
color: selected ? Meui.Theme.highlightColor : _mouseArea.containsMouse ? control.hoveredColor : "transparent"
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: Meui.Units.smallSpacing
anchors.rightMargin: Meui.Units.smallSpacing
spacing: Meui.Units.largeSpacing
Item {
id: iconItem
Layout.fillHeight: true
width: parent.height * 0.8
PlasmaCore.IconItem {
id: icon
z: 2
anchors.fill: parent
animated: false
usesPlasmaTheme: false
smooth: true
source: model.blank ? "" : model.decoration
overlays: model.blank ? "" : model.overlays
}
}
Label {
id: label1
Layout.fillWidth: true
text: name
color: selected ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
}
Label {
id: label2
color: selected ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
}
}
}

91
qml/FolderListItem.qml Normal file
View file

@ -0,0 +1,91 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import MeuiKit 1.0 as Meui
Item {
id: _listItem
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
height: 40
Accessible.name: fileName
Accessible.role: Accessible.Canvas
property Item iconArea: _image.visible ? _image : _icon
property Item textArea: _label
property int index: model.index
property bool hovered: ListView.view.hoveredItem === _listItem
property bool selected: model.selected
property bool blank: model.blank
property color hoveredColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.backgroundColor, 1.1)
: Qt.darker(Meui.Theme.backgroundColor, 1.05)
property color selectedColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.backgroundColor, 1.2)
: Qt.darker(Meui.Theme.backgroundColor, 1.15)
// onSelectedChanged: {
// if (selected && !blank) {
// _listItem.grabToImage(function(result) {
// folderModel.addItemDragImage(_listItem.index,
// _listItem.x,
// _listItem.y,
// _listItem.width, _listItem.height, result.image)
// })
// }
// }
Rectangle {
id: _background
anchors.fill: parent
radius: Meui.Theme.smallRadius
color: selected ? selectedColor : hovered ? hoveredColor : "transparent"
visible: selected || hovered
}
RowLayout {
id: _mainLayout
anchors.fill: parent
anchors.leftMargin: Meui.Units.smallSpacing
anchors.rightMargin: Meui.Units.smallSpacing
spacing: Meui.Units.largeSpacing
Item {
id: iconItem
Layout.fillHeight: true
width: parent.height * 0.8
Image {
id: _icon
anchors.centerIn: iconItem
width: iconItem.width
height: width
sourceSize.width: width
sourceSize.height: height
source: "image://icontheme/" + model.iconName
visible: !_image.visible
asynchronous: true
}
Image {
id: _image
width: parent.height * 0.8
height: width
anchors.centerIn: iconItem
sourceSize: Qt.size(_icon.width, _icon.height)
source: model.thumbnail ? model.thumbnail : ""
visible: _image.status === Image.Ready
fillMode: Image.PreserveAspectFit
asynchronous: true
smooth: false
}
}
Label {
id: _label
text: model.fileName
Layout.fillWidth: true
color: Meui.Theme.textColor
elide: Qt.ElideMiddle
}
}
}

View file

@ -1,38 +1,364 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import MeuiKit 1.0 as Meui import MeuiKit 1.0 as Meui
import Cutefish.FileManager 1.0 as FM import Cutefish.FileManager 1.0
ListView { ListView {
id: control id: control
signal clicked(var mouse) property Item rubberBand: null
signal positionChanged(var mouse) property Item hoveredItem: null
signal pressed(var mouse) property Item pressedItem: null
signal released(var mouse)
ScrollBar.vertical: ScrollBar {} property int verticalDropHitscanOffset: 0
spacing: Meui.Units.largeSpacing
property int pressX: -1
property int pressY: -1
property int dragX: -1
property int dragY: -1
property bool ctrlPressed: false
property bool shiftPressed: false
property int previouslySelectedItemIndex: -1
property variant cPress: null
property Item editor: null
property int anchorIndex: 0
signal keyPress(var event)
currentIndex: -1
clip: true clip: true
snapMode: ListView.NoSnap ScrollBar.vertical: ScrollBar {
bottomPadding: Meui.Theme.mediumRadius
}
highlightFollowsCurrentItem: true
highlightMoveDuration: 0 highlightMoveDuration: 0
highlightResizeDuration : 0 keyNavigationEnabled : true
keyNavigationWraps : true
Keys.onPressed: {
if (event.key === Qt.Key_Control) {
ctrlPressed = true
} else if (event.key === Qt.Key_Shift) {
shiftPressed = true
if (currentIndex != -1)
anchorIndex = currentIndex
}
control.keyPress(event)
}
Keys.onReleased: {
if (event.key === Qt.Key_Control) {
ctrlPressed = false
} else if (event.key === Qt.Key_Shift) {
shiftPressed = false
anchorIndex = 0
}
}
onContentXChanged: {
cancelRename()
}
onContentYChanged: {
cancelRename()
}
onPressXChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
onPressYChanged: {
cPress = mapToItem(control.contentItem, pressX, pressY)
}
function rename() {
if (currentIndex !== -1) {
var renameAction = control.model.action("rename")
if (renameAction && !renameAction.enabled)
return
if (!control.editor)
control.editor = editorComponent.createObject(control)
control.editor.targetItem = control.currentItem
}
}
function cancelRename() {
if (control.editor)
control.editor = null
}
MouseArea { MouseArea {
id: _mouseArea
anchors.fill: parent anchors.fill: parent
z: -1
hoverEnabled: true
propagateComposedEvents: true propagateComposedEvents: true
acceptedButtons: Qt.LeftButton | Qt.RightButton preventStealing: true
onClicked: parent.clicked(mouse) acceptedButtons: Qt.RightButton | Qt.LeftButton
onPositionChanged: parent.positionChanged(mouse) hoverEnabled: true
onPressed: parent.pressed(mouse) enabled: true
onReleased: parent.released(mouse) z: -1
Keys.forwardTo: _listViewBrowser
onDoubleClicked: {
if (mouse.button === Qt.LeftButton && control.pressedItem)
folderModel.openSelected()
}
onPressed: {
control.forceActiveFocus()
if (control.editor && childAt(mouse.x, mouse.y) !== control.editor)
control.editor.commit()
if (mouse.source === Qt.MouseEventSynthesizedByQt) {
var index = control.indexAt(mouse.x, mouse.y + control.contentY)
var indexItem = control.itemAtIndex(index)
if (indexItem && indexItem.iconArea) {
control.currentIndex = index
hoveredItem = indexItem
} else {
hoveredItem = null
}
}
pressX = mouse.x
pressY = mouse.y
if (!hoveredItem || hoveredItem.blank) {
if (!control.ctrlPressed) {
control.currentIndex = -1
control.previouslySelectedItemIndex = -1
folderModel.clearSelection()
}
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
} else {
pressedItem = hoveredItem
if (control.shiftPressed && control.currentIndex !== -1) {
folderModel.setRangeSelected(control.anchorIndex, hoveredItem.index)
} else {
if (!control.ctrlPressed && !folderModel.isSelected(hoveredItem.index)) {
previouslySelectedItemIndex = -1
folderModel.clearSelection()
}
if (control.ctrlPressed)
folderModel.toggleSelected(hoveredItem.index)
else
folderModel.setSelected(hoveredItem.index)
}
control.currentIndex = hoveredItem.index
if (mouse.buttons & Qt.RightButton) {
clearPressState()
folderModel.openContextMenu(null, mouse.modifiers)
mouse.accepted = true
}
}
}
onClicked: {
clearPressState()
if (!hoveredItem || hoveredItem.blank || control.currentIndex === -1 || control.ctrlPressed
|| control.shiftPressed) {
return
}
// TODO: rename
}
onPositionChanged: {
control.ctrlPressed = (mouse.modifiers & Qt.ControlModifier)
control.shiftPressed = (mouse.modifiers & Qt.ShiftModifier)
var cPos = mapToItem(control.contentItem, mouse.x, mouse.y)
var item = control.itemAt(mouse.x, mouse.y + control.contentY)
var leftEdge = Math.min(control.contentX, control.originX)
if (!item || item.blank) {
if (control.hoveredItem) {
control.hoveredItem = null
}
} else {
control.hoveredItem = item
}
// TODO: autoscroll
if (control.rubberBand) {
var rB = control.rubberBand
if (cPos.x < cPress.x) {
rB.x = Math.max(leftEdge, cPos.x)
rB.width = Math.abs(rB.x - cPress.x)
} else {
rB.x = cPress.x
var ceil = Math.max(control.width, control.contentItem.width) + leftEdge
rB.width = Math.min(ceil - rB.x, Math.abs(rB.x - cPos.x))
}
if (cPos.y < cPress.y) {
rB.y = Math.max(0, cPos.y)
rB.height = Math.abs(rB.y - cPress.y)
} else {
rB.y = cPress.y
var ceilValue = Math.max(control.height, control.contentItem.height)
rB.height = Math.min(ceilValue - rB.y, Math.abs(rB.y - cPos.y))
}
// Ensure rubberband is at least 1px in size or else it will become
// invisible and not match any items.
rB.width = Math.max(1, rB.width)
rB.height = Math.max(1, rB.height)
control.rectangleSelect(rB.x, rB.y, rB.width, rB.height)
return
}
// Drag
if (pressX != -1) {
if (pressedItem != null && folderModel.isSelected(pressedItem.index)) {
control.dragX = mouse.x
control.dragY = mouse.y
control.verticalDropHitscanOffset = pressedItem.y + (pressedItem.height / 2)
folderModel.dragSelected(mouse.x, mouse.y)
control.dragX = -1
control.dragY = -1
clearPressState()
} else {
folderModel.pinSelection()
control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y})
control.interactive = false
}
}
}
onContainsMouseChanged: {
if (!containsMouse && !control.rubberBand) {
clearPressState()
if (control.hoveredItem) {
control.hoveredItem = null
}
}
}
onReleased: pressCanceled()
onCanceled: pressCanceled()
}
function pressCanceled() {
if (control.rubberBand) {
control.rubberBand.close()
control.rubberBand = null
control.interactive = true
// control.cachedRectangleSelection = null
folderModel.unpinSelection()
}
clearPressState()
// control.cancelAutoscroll()
}
function clearPressState() {
pressedItem = null
pressX = -1
pressY = -1
}
function rectangleSelect(x, y, width, height) {
}
function updateSelection(modifier) {
if (modifier & Qt.ShiftModifier) {
folderModel.setRangeSelected(anchorIndex, hoveredItem)
} else {
folderModel.clear()
folderModel.setSelected(currentIndex)
if (currentIndex == -1)
previouslySelectedItemIndex = -1
previouslySelectedItemIndex = currentIndex
}
}
Component {
id: editorComponent
TextArea {
id: _editor
visible: false
wrapMode: Text.NoWrap
textMargin: 0
verticalAlignment: TextEdit.AlignVCenter
property Item targetItem: null
background: Item {}
onTargetItemChanged: {
if (targetItem != null) {
var pos = control.mapFromItem(targetItem, targetItem.textArea.x, control.contentY)
width = targetItem.width - targetItem.iconArea.width * 2
height = targetItem.height
x = pos.x
y = pos.y
text = targetItem.textArea.text
targetItem.textArea.visible = false
_editor.select(0, folderModel.fileExtensionBoundary(targetItem.index))
visible = true
} else {
x: 0
y: 0
visible = false
}
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
commit()
break
case Qt.Key_Escape:
if (targetItem) {
targetItem.textArea.visible = true
targetItem = null
event.accepted = true
}
break
}
}
onVisibleChanged: {
if (visible)
_editor.forceActiveFocus()
else
control.forceActiveFocus()
}
function commit() {
if (targetItem) {
targetItem.textArea.visible = true
folderModel.rename(targetItem.index, text)
control.currentIndex = targetItem.index
targetItem = null
}
}
}
} }
} }

213
qml/FolderPage.qml Normal file
View file

@ -0,0 +1,213 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
import "./Dialogs"
Item {
id: folderPage
property alias currentUrl: folderModel.url
property Item currentView: _viewLoader.item
property int statusBarHeight: 30 + Meui.Units.smallSpacing
signal requestPathEditor()
onCurrentUrlChanged: {
_viewLoader.item.forceActiveFocus()
}
Rectangle {
id: _background
anchors.fill: parent
radius: Meui.Theme.smallRadius
color: Meui.Theme.backgroundColor
}
Label {
id: _fileTips
text: qsTr("No files")
anchors.centerIn: parent
visible: false
}
FolderModel {
id: folderModel
viewAdapter: viewAdapter
Component.onCompleted: {
folderModel.url = folderModel.homePath()
}
}
ItemViewAdapter {
id: viewAdapter
adapterView: _viewLoader.item
adapterModel: folderModel
adapterIconSize: 40
adapterVisibleArea: Qt.rect(_viewLoader.item.contentX, _viewLoader.item.contentY,
_viewLoader.item.contentWidth, _viewLoader.item.contentHeight)
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Loader {
id: _viewLoader
Layout.fillWidth: true
Layout.fillHeight: true
sourceComponent: switch (settings.viewMethod) {
case 0: return _listViewComponent
case 1: return _gridViewComponent
}
}
Loader {
Layout.fillWidth: true
sourceComponent: _statusBar
}
}
Component {
id: _statusBar
Item {
height: statusBarHeight
z: 999
RowLayout {
anchors.fill: parent
anchors.leftMargin: Meui.Units.largeSpacing
anchors.rightMargin: Meui.Units.largeSpacing
anchors.bottomMargin: Meui.Units.smallSpacing
Label {
text: folderModel.statusText
Layout.alignment: Qt.AlignLeft
elide: Text.ElideMiddle
}
Button {
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
text: qsTr("Empty Trash")
onClicked: folderModel.emptyTrash()
visible: folderModel.url === "trash:/"
}
}
}
}
Component {
id: _gridViewComponent
FolderGridView {
id: _gridView
model: folderModel
delegate: FolderGridItem {}
onCountChanged: {
_fileTips.visible = count === 0
}
}
}
Component {
id: _listViewComponent
FolderListView {
id: _folderListView
model: folderModel
leftMargin: Meui.Units.largeSpacing
rightMargin: Meui.Units.largeSpacing
spacing: Meui.Units.largeSpacing
onCountChanged: {
_fileTips.visible = count === 0
}
delegate: FolderListItem {}
Component.onCompleted: {
folderModel.requestRename.connect(rename)
}
}
}
Component {
id: rubberBandObject
RubberBand {
id: rubberBand
width: 0
height: 0
z: 99999
color: Meui.Theme.highlightColor
function close() {
opacityAnimation.restart()
}
OpacityAnimator {
id: opacityAnimation
target: rubberBand
to: 0
from: 1
duration: 150
easing {
bezierCurve: [0.4, 0.0, 1, 1]
type: Easing.Bezier
}
onFinished: {
rubberBand.visible = false
rubberBand.enabled = false
rubberBand.destroy()
}
}
}
}
Connections {
target: _viewLoader.item
function onKeyPress(event) {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return)
folderModel.openSelected()
else if (event.key === Qt.Key_C && event.modifiers & Qt.ControlModifier)
folderModel.copy()
else if (event.key === Qt.Key_X && event.modifiers & Qt.ControlModifier)
folderModel.cut()
else if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier)
folderModel.paste()
else if (event.key === Qt.Key_F2)
folderModel.requestRename()
else if (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
folderPage.requestPathEditor()
else if (event.key === Qt.Key_A && event.modifiers & Qt.ControlModifier)
folderModel.selectAll()
else if (event.key === Qt.Key_Backspace)
folderModel.up()
}
}
function openUrl(url) {
folderModel.url = url
_viewLoader.item.forceActiveFocus()
}
function goBack() {
folderModel.goBack()
}
function goForward() {
folderModel.goForward()
}
}

View file

@ -1,11 +1,11 @@
import QtQuick 2.0 import QtQuick 2.12
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
Settings { Settings {
property int viewMethod: 0 // 0 = Grid, 1 = List property int viewMethod: 0
property bool showHidden: false property bool showHidden: false
property int width: 1080 property int width: 900
property int height: 645 property int height: 580
property int desktopIconSize: 128 property int desktopIconSize: 128
property int maximumIconSize: 256 property int maximumIconSize: 256
property int minimumIconSize: 128 property int minimumIconSize: 128

View file

@ -1,102 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: main
property int index: model.index
property string name: model.blank ? "" : model.display
property bool blank: model.blank
property bool isDir: model.blank ? false : model.isDir
property bool selected: model.blank ? false : model.selected
property Item frame: contentItem
property Item iconArea: icon
property Item labelArea: label
property bool hovered: (main.GridView.view.hoveredItem === main)
property color hoveredColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.1)
property color selectedColor: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.9)
Accessible.name: name
Accessible.role: Accessible.Canvas
onSelectedChanged: {
if (selected && !blank) {
contentItem.grabToImage(function(result) {
dir.addItemDragImage(positioner.map(index), main.x + contentItem.x, main.y + contentItem.y, contentItem.width, contentItem.height, result.image);
});
}
}
Rectangle {
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
radius: Meui.Theme.bigRadius
color: selected ? selectedColor : main.hovered ? hoveredColor : "transparent"
border.color: Qt.rgba(Meui.Theme.highlightColor.r,
Meui.Theme.highlightColor.g,
Meui.Theme.highlightColor.b, 0.3)
border.width: main.hovered || selected ? 1 : 0
}
Item {
id: contentItem
anchors.fill: parent
anchors.margins: Meui.Units.largeSpacing
PlasmaCore.IconItem {
id: icon
z: 2
anchors.top: parent.top
anchors.topMargin: Meui.Units.smallSpacing
anchors.horizontalCenter: parent.horizontalCenter
height: main.height * 0.55
width: height
animated: false
usesPlasmaTheme: false
smooth: true
source: model.blank ? "" : model.decoration
overlays: model.blank ? "" : model.overlays
}
Label {
id: label
z: 2
anchors.top: icon.bottom
anchors.topMargin: Meui.Units.smallSpacing
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width
textFormat: Text.PlainText
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignTop
wrapMode: Text.Wrap
elide: Text.ElideRight
color: Meui.Theme.textColor
opacity: model.isHidden ? 0.6 : 1
text: model.blank ? "" : model.display
font.italic: model.isLink
}
}
}

View file

@ -1,101 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
Menu {
id: control
implicitWidth: 200
property var item : ({})
property int index : -1
property bool isDir : false
property bool isExec : false
signal openClicked(var item)
signal removeClicked(var item)
signal copyClicked(var item)
signal cutClicked(var item)
signal renameClicked(var item)
signal wallpaperClicked(var item)
signal propertiesClicked(var item)
MenuItem {
text: qsTr("Open")
onTriggered: {
openClicked(control.item)
close()
}
}
MenuItem {
text: qsTr("Copy")
onTriggered: {
copyClicked(control.item)
close()
}
}
MenuItem {
text: qsTr("Cut")
onTriggered: {
cutClicked(control.item)
close()
}
}
MenuItem {
text: qsTr("Move to Trash")
onTriggered: {
removeClicked(control.item)
close()
}
}
MenuSeparator {}
MenuItem {
text: qsTr("Rename")
onTriggered: {
renameClicked(control.item)
close()
}
}
MenuItem {
text: qsTr("Open in Terminal")
}
MenuItem {
id: wallpaperItem
text: qsTr("Set As Wallpaper")
visible: false
onTriggered: {
wallpaperClicked(control.item)
close()
}
}
MenuItem {
id: properties
text: qsTr("Properties")
onTriggered: {
propertiesClicked(control.item)
close()
}
}
function show(index) {
control.item = currentFMModel.get(index)
if (item) {
control.index = index
control.isDir = item.isdir === true || item.isdir === "true"
control.isExec = item.executable === true || item.executable === "true"
wallpaperItem.visible = item.img === "true"
popup()
}
}
}

View file

@ -1,106 +1,80 @@
import QtQuick 2.4 import QtQuick 2.12
import QtQuick.Controls 2.4 import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
import Cutefish.FileManager 1.0 import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui
Item { Item {
id: control id: control
property string url: "" property string url: ""
signal placeClicked(string path)
signal pathChanged(string path)
onUrlChanged: { signal itemClicked(string path)
_pathList.path = control.url signal editorAccepted(string path)
}
BaseModel {
id: _pathModel
list: _pathList
}
PathList {
id: _pathList
}
Rectangle {
anchors.fill: parent
radius: Meui.Theme.smallRadius
color: Meui.Theme.backgroundColor
}
ListView { ListView {
id: listView id: _pathView
anchors.fill: parent anchors.fill: parent
model: _pathModel model: _pathBarModel
orientation: Qt.Horizontal orientation: Qt.Horizontal
layoutDirection: Qt.LeftToRight layoutDirection: Qt.LeftToRight
clip: true clip: true
leftMargin: 3
rightMargin: 3
spacing: Meui.Units.smallSpacing spacing: Meui.Units.smallSpacing
onCountChanged: { onCountChanged: {
currentIndex = listView.count - 1 _pathView.currentIndex = _pathView.count - 1
listView.positionViewAtEnd() _pathView.positionViewAtEnd()
} }
delegate: MouseArea {
id: pathBarItem
height: listView.height
width: label.width + Meui.Units.largeSpacing * 2
property bool selected: index === listView.count - 1
property color pressedColor: Qt.rgba(Meui.Theme.textColor.r,
Meui.Theme.textColor.g,
Meui.Theme.textColor.b, 0.5)
onClicked: control.placeClicked(model.path)
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: 2 color: Meui.Theme.backgroundColor
color: Meui.Theme.highlightColor
radius: Meui.Theme.smallRadius radius: Meui.Theme.smallRadius
visible: selected z: -1
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 2
samples: 2
horizontalOffset: 0
verticalOffset: 0
color: Qt.rgba(0, 0, 0, 0.1)
}
}
Label {
id: label
text: model.label
anchors.centerIn: parent
color: selected ? Meui.Theme.highlightedTextColor : pathBarItem.pressed
? pressedColor : Meui.Theme.textColor
}
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: openEditor()
z: -1
}
delegate: MouseArea {
id: _item
height: ListView.view.height
width: _name.width + Meui.Units.largeSpacing
z: -1 z: -1
onClicked: { property bool selected: index === _pathView.count - 1
if (!addressEdit.visible) {
openEditor() onClicked: control.itemClicked(model.path)
Rectangle {
anchors.fill: parent
anchors.topMargin: 2
anchors.bottomMargin: 2
color: Meui.Theme.highlightColor
radius: Meui.Theme.smallRadius
visible: selected
} }
Label {
id: _name
text: model.name
color: selected ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
anchors.centerIn: parent
} }
} }
} }
TextField { TextField {
id: addressEdit id: _pathEditor
anchors.centerIn: parent anchors.fill: parent
width: parent.width
height: parent.height
visible: false visible: false
selectByMouse: true selectByMouse: true
inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase
@ -108,7 +82,7 @@ Item {
text: control.url text: control.url
onAccepted: { onAccepted: {
control.pathChanged(text) control.editorAccepted(text)
closeEditor() closeEditor()
} }
@ -124,15 +98,25 @@ Item {
} }
} }
function closeEditor() { PathBarModel {
addressEdit.visible = false id: _pathBarModel
listView.visible = true }
function updateUrl(url) {
control.url = url
_pathBarModel.url = url
} }
function openEditor() { function openEditor() {
addressEdit.visible = true _pathEditor.text = control.url
addressEdit.forceActiveFocus() _pathEditor.visible = true
addressEdit.selectAll() _pathEditor.forceActiveFocus()
listView.visible = false _pathEditor.selectAll()
_pathView.visible = false
}
function closeEditor() {
_pathEditor.visible = false
_pathView.visible = true
} }
} }

View file

@ -1,55 +1,28 @@
import QtQuick 2.4 import QtQuick 2.12
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.12
import QtQuick.Controls 2.4 import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui import MeuiKit 1.0 as Meui
import Cutefish.FileManager 1.0 import Cutefish.FileManager 1.0
ListView { ListView {
id: control id: sideBar
implicitWidth: 200
property string currentUrl signal clicked(string path)
signal placeClicked(string path)
signal itemClicked(int index)
onItemClicked: {
var item = placesModel.get(index)
control.placeClicked(item.url)
}
onCurrentUrlChanged: {
syncIndex(currentUrl)
}
Component.onCompleted: {
syncIndex(currentUrl)
}
function syncIndex(path) {
control.currentIndex = -1
for (var i = 0; i < control.count; ++i) {
if (path === control.model.get(i).url) {
control.currentIndex = i
break
}
}
}
PlacesModel { PlacesModel {
id: placesModel id: placesModel
} }
model: placesModel
clip: true clip: true
spacing: Meui.Units.smallSpacing
leftMargin: Meui.Units.smallSpacing leftMargin: Meui.Units.smallSpacing
rightMargin: Meui.Units.smallSpacing rightMargin: Meui.Units.smallSpacing
spacing: Meui.Units.largeSpacing
model: placesModel
ScrollBar.vertical: ScrollBar {} ScrollBar.vertical: ScrollBar {}
flickableDirection: Flickable.VerticalFlick
highlightFollowsCurrentItem: true highlightFollowsCurrentItem: true
highlightMoveDuration: 0 highlightMoveDuration: 0
@ -60,15 +33,71 @@ ListView {
color: Meui.Theme.highlightColor color: Meui.Theme.highlightColor
} }
delegate: SidebarItem { delegate: Item {
id: listItem id: _item
checked: control.currentIndex === index
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
height: 40 height: 40
property bool checked: sideBar.currentIndex === index
property color hoveredColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.backgroundColor, 1.1)
: Qt.darker(Meui.Theme.backgroundColor, 1.1)
MouseArea {
id: _mouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onClicked: { onClicked: {
control.currentIndex = index sideBar.currentIndex = index
control.itemClicked(index) sideBar.clicked(model.path)
}
}
Rectangle {
anchors.fill: parent
radius: Meui.Theme.smallRadius
color: _mouseArea.containsMouse && !checked ? _item.hoveredColor : "transparent"
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: Meui.Units.smallSpacing
anchors.rightMargin: Meui.Units.smallSpacing
spacing: Meui.Units.smallSpacing
Image {
height: _item.height * 0.55
width: height
sourceSize: Qt.size(width, height)
source: model.iconPath ? model.iconPath : "image://icontheme/" + model.iconName
Layout.alignment: Qt.AlignVCenter
ColorOverlay {
anchors.fill: parent
source: parent
color: _label.color
visible: Meui.Theme.darkMode && model.iconPath || checked
}
}
Label {
id: _label
text: model.name
color: checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
elide: Text.ElideRight
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
}
}
function updateSelection(path) {
sideBar.currentIndex = -1
for (var i = 0; i < sideBar.count; ++i) {
if (path === sideBar.model.get(i).path) {
sideBar.currentIndex = i
break
}
} }
} }
} }

View file

@ -1,69 +0,0 @@
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import MeuiKit 1.0 as Meui
Item {
id: item
property bool checked: false
signal clicked
Rectangle {
id: rect
anchors.fill: parent
radius: Meui.Theme.smallRadius
color: item.checked ? "transparent"
: mouseArea.containsMouse ? Qt.rgba(Meui.Theme.textColor.r,
Meui.Theme.textColor.g,
Meui.Theme.textColor.b, 0.1) : "transparent"
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onClicked: item.clicked()
}
RowLayout {
anchors.fill: rect
anchors.leftMargin: Meui.Units.largeSpacing
anchors.rightMargin: Meui.Units.largeSpacing
spacing: Meui.Units.largeSpacing
Item {
id: iconItem
height: item.height * 0.55
width: height
Image {
id: image
anchors.fill: parent
sourceSize: Qt.size(width, height)
source: model.iconPath ? model.iconPath : "image://icontheme/" + model.iconName
Layout.alignment: Qt.AlignVCenter
}
ColorOverlay {
anchors.fill: parent
source: parent
color: itemTitle.color
visible: Meui.Theme.darkMode && model.iconPath || checked
}
}
Label {
id: itemTitle
text: model.name
color: item.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
elide: Text.ElideRight
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
}
}
}

View file

@ -1,105 +1,122 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12 import QtQuick.Window 2.12
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import Cutefish.FileManager 1.0
import MeuiKit 1.0 as Meui import MeuiKit 1.0 as Meui
import "./Controls"
Meui.Window { Meui.Window {
id: root id: root
width: settings.width width: settings.width
height: settings.height height: settings.height
minimumWidth: 900 minimumWidth: 900
minimumHeight: 600 minimumHeight: 580
visible: true visible: true
title: qsTr("File Manager") title: qsTr("File Manager")
hideHeaderOnMaximize: false
headerBarHeight: 35 + Meui.Units.largeSpacing headerBarHeight: 35 + Meui.Units.largeSpacing
backgroundColor: Meui.Theme.secondBackgroundColor backgroundColor: Meui.Theme.secondBackgroundColor
property QtObject settings: GlobalSettings { } property QtObject settings: GlobalSettings { }
onClosing: { onClosing: {
if (root.visibility !== Window.Maximized &&
root.visibility !== Window.FullScreen) {
settings.width = root.width settings.width = root.width
settings.height = root.height settings.height = root.height
} }
}
headerBar: Item { headerBar: Item {
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: Meui.Units.largeSpacing anchors.leftMargin: Meui.Units.smallSpacing
anchors.rightMargin: Meui.Units.smallSpacing anchors.rightMargin: Meui.Units.smallSpacing
anchors.topMargin: Meui.Units.largeSpacing anchors.topMargin: Meui.Units.smallSpacing
anchors.bottomMargin: Meui.Units.smallSpacing
spacing: Meui.Units.smallSpacing spacing: Meui.Units.smallSpacing
IconButton { IconButton {
Layout.fillHeight: true Layout.fillHeight: true
implicitWidth: height implicitWidth: height
source: Meui.Theme.darkMode ? "qrc:/images/dark/go-previous.svg" : "qrc:/images/light/go-previous.svg" source: Meui.Theme.darkMode ? "qrc:/images/dark/go-previous.svg"
onClicked: _browserView.goBack() : "qrc:/images/light/go-previous.svg"
onClicked: _folderPage.goBack()
} }
IconButton { IconButton {
Layout.fillHeight: true Layout.fillHeight: true
implicitWidth: height implicitWidth: height
source: Meui.Theme.darkMode ? "qrc:/images/dark/go-next.svg" : "qrc:/images/light/go-next.svg" source: Meui.Theme.darkMode ? "qrc:/images/dark/go-next.svg"
onClicked: _browserView.goForward() : "qrc:/images/light/go-next.svg"
onClicked: _folderPage.goForward()
} }
PathBar { PathBar {
id: pathBar id: _pathBar
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
url: _browserView.url onItemClicked: _folderPage.openUrl(path)
onPlaceClicked: _browserView.openFolder(path) onEditorAccepted: _folderPage.openUrl(path)
onPathChanged: _browserView.openFolder(path)
} }
IconButton { IconButton {
Layout.fillHeight: true Layout.fillHeight: true
implicitWidth: height implicitWidth: height
source: Meui.Theme.darkMode ? "qrc:/images/dark/grid.svg" : "qrc:/images/light/grid.svg"
onClicked: settings.viewMethod = 1
}
IconButton { property var gridSource: Meui.Theme.darkMode ? "qrc:/images/dark/grid.svg" : "qrc:/images/light/grid.svg"
Layout.fillHeight: true property var listSource: Meui.Theme.darkMode ? "qrc:/images/dark/list.svg" : "qrc:/images/light/list.svg"
implicitWidth: height
source: Meui.Theme.darkMode ? "qrc:/images/dark/list.svg" : "qrc:/images/light/list.svg" source: settings.viewMethod === 0 ? listSource : gridSource
onClicked: settings.viewMethod = 0
} onClicked: {
if (settings.viewMethod === 1)
settings.viewMethod = 0
else
settings.viewMethod = 1
} }
} }
ColumnLayout { // IconButton {
anchors.fill: parent // Layout.fillHeight: true
spacing: Meui.Units.largeSpacing // implicitWidth: height
// source: Meui.Theme.darkMode ? "qrc:/images/dark/grid.svg" : "qrc:/images/light/grid.svg"
// onClicked: settings.viewMethod = 1
// }
Item { // IconButton {
id: bottomControls // Layout.fillHeight: true
Layout.fillWidth: true // implicitWidth: height
Layout.fillHeight: true // source: Meui.Theme.darkMode ? "qrc:/images/dark/list.svg" : "qrc:/images/light/list.svg"
// onClicked: settings.viewMethod = 0
// }
}
}
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: Meui.Units.largeSpacing anchors.topMargin: 2
spacing: 0 spacing: 0
SideBar { SideBar {
id: _sideBar
Layout.fillHeight: true Layout.fillHeight: true
currentUrl: _browserView.model.url width: 200 + Meui.Units.largeSpacing
onPlaceClicked: _browserView.model.url = path onClicked: _folderPage.openUrl(path)
} }
BrowserView { FolderPage {
id: _browserView id: _folderPage
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
// onOpenPathBar: pathBar.openEditor() onCurrentUrlChanged: {
_sideBar.updateSelection(currentUrl)
_pathBar.updateUrl(currentUrl)
} }
onRequestPathEditor: {
_pathBar.openEditor()
} }
} }
} }

View file

@ -1,86 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 "baselist.h"
#include "basemodel.h"
BaseList::BaseList(QObject *parent)
: QObject(parent)
, m_model(nullptr)
{
}
int BaseList::getCount() const
{
return this->items().count();
}
QVariantMap BaseList::get(const int &index) const
{
if (this->m_model) {
return this->m_model->get(index);
}
if (index >= 0 && this->items().size() > 0 && index < this->items().size()) {
return FMH::toMap(this->items()[index]);
}
return QVariantMap();
}
FMH::MODEL_LIST BaseList::getItems() const
{
if (this->m_model && !this->m_model->getFilter().isEmpty()) {
return FMH::toModelList(this->m_model->getAll());
}
return this->items();
}
int BaseList::mappedIndex(const int &index) const
{
if (this->m_model)
return this->m_model->mappedToSource(index);
return index;
}
int BaseList::mappedIndexFromSource(const int &index) const
{
if (this->m_model)
return this->m_model->mappedFromSource(index);
return index;
}
bool BaseList::exists(const FMH::MODEL_KEY &key, const QString &value) const
{
return this->indexOf(key, value) >= 0;
}
int BaseList::indexOf(const FMH::MODEL_KEY &key, const QString &value) const
{
const auto it = std::find_if(this->items().constBegin(), this->items().constEnd(), [&](const FMH::MODEL &item) -> bool {
return item[key] == value;
});
if (it != this->items().constEnd())
return this->mappedIndexFromSource(std::distance(this->items().constBegin(), it));
else
return -1;
}

View file

@ -1,89 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 BASELIST_H
#define BASELIST_H
#include "fmh.h"
#include <QQmlParserStatus>
/**
* @todo write docs
*/
#include <QObject>
class BaseModel;
class BaseList : public QObject, public QQmlParserStatus
{
Q_INTERFACES(QQmlParserStatus)
Q_OBJECT
Q_PROPERTY(int count READ getCount NOTIFY countChanged FINAL)
public:
/**
* Default constructor
*/
explicit BaseList(QObject *parent = nullptr);
virtual const FMH::MODEL_LIST &items() const = 0;
virtual void classBegin() override
{
}
virtual void componentComplete() override
{
}
virtual void modelHooked() {};
int getCount() const;
/**
* @brief getItems
* Get all the items in the list model. If the model has been filtered or sorted those are the items that are returned
* @param index
* @return
*/
FMH::MODEL_LIST getItems() const;
const BaseModel *m_model; // becarefull this is owned by qml engine, this is only supossed to be a viewer
public slots:
int mappedIndex(const int &index) const;
int mappedIndexFromSource(const int &index) const;
QVariantMap get(const int &index) const;
protected:
bool exists(const FMH::MODEL_KEY &key, const QString &value) const;
int indexOf(const FMH::MODEL_KEY &key, const QString &value) const;
signals:
void preItemAppended();
void preItemsAppended(uint count);
void postItemAppended();
void preItemAppendedAt(int index);
void preItemRemoved(int index);
void postItemRemoved();
void updateModel(int index, QVector<int> roles);
void preListChanged();
void postListChanged();
void countChanged();
};
#endif // BASELIST_H

View file

@ -1,333 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 "basemodel.h"
#include "baselist.h"
BaseModel::BaseModel(QObject *parent)
: QSortFilterProxyModel(parent)
, m_model(new PrivateAbstractListModel(this))
{
this->setSourceModel(this->m_model);
this->setDynamicSortFilter(true);
}
void BaseModel::setFilterString(const QString &string)
{
this->setFilterCaseSensitivity(Qt::CaseInsensitive);
this->setFilterFixedString(string);
// this->setFilterRegExp(QRegExp(string, Qt::CaseInsensitive));
}
void BaseModel::setSortOrder(const int &sortOrder)
{
this->sort(0, static_cast<Qt::SortOrder>(sortOrder));
}
QVariantMap BaseModel::get(const int &index) const
{
QVariantMap res;
if (index >= this->rowCount() || index < 0)
return res;
const auto roleNames = this->roleNames();
for (const auto &role : roleNames)
res.insert(role, this->index(index, 0).data(FMH::MODEL_NAME_KEY[role]).toString());
return res;
}
QVariantList BaseModel::getAll() const
{
QVariantList res;
for (auto i = 0; i < this->rowCount(); i++)
res << this->get(i);
return res;
}
void BaseModel::setFilter(const QString &filter)
{
if (this->m_filter == filter)
return;
this->m_filter = filter;
emit this->filterChanged(this->m_filter);
this->setFilterFixedString(this->m_filter);
}
const QString BaseModel::getFilter() const
{
return this->m_filter;
}
void BaseModel::setSortOrder(const Qt::SortOrder &sortOrder)
{
if (this->m_sortOrder == sortOrder)
return;
this->m_sortOrder = sortOrder;
emit this->sortOrderChanged(this->m_sortOrder);
this->sort(0, this->m_sortOrder);
}
Qt::SortOrder BaseModel::getSortOrder() const
{
return this->m_sortOrder;
}
void BaseModel::setSort(const QString &sort)
{
if (this->m_sort == sort)
return;
this->m_sort = sort;
emit this->sortChanged(this->m_sort);
this->setSortRole(FMH::MODEL_NAME_KEY[sort]);
this->sort(0, this->m_sortOrder);
}
QString BaseModel::getSort() const
{
return this->m_sort;
}
int BaseModel::mappedFromSource(const int &index) const
{
return this->mapFromSource(this->m_model->index(index, 0)).row();
}
int BaseModel::mappedToSource(const int &index) const
{
return this->mapToSource(this->index(index, 0)).row();
}
bool BaseModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (this->filterRole() != Qt::DisplayRole) {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const auto data = this->sourceModel()->data(index, this->filterRole()).toString();
return data.contains(this->filterRegExp());
}
const auto roleNames = this->sourceModel()->roleNames();
for (const auto &role : roleNames) {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const auto data = this->sourceModel()->data(index, FMH::MODEL_NAME_KEY[role]).toString();
if (data.contains(this->filterRegExp()))
return true;
else
continue;
}
return false;
}
BaseList *BaseModel::getList() const
{
return this->m_model->getList();
}
BaseList *BaseModel::PrivateAbstractListModel::getList() const
{
return this->list;
}
void BaseModel::PrivateAbstractListModel::setList(BaseList *value)
{
beginResetModel();
if (this->list)
this->list->disconnect(this);
this->list = value;
if (this->list) {
connect(
this->list,
&BaseList::preItemAppendedAt,
this,
[=](int index) {
beginInsertRows(QModelIndex(), index, index);
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::preItemAppended,
this,
[=]() {
const int index = this->list->items().size();
beginInsertRows(QModelIndex(), index, index);
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::preItemsAppended,
this,
[=](uint count) {
const int index = this->list->items().size();
beginInsertRows(QModelIndex(), index, index + count - 1);
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::postItemAppended,
this,
[=]() {
endInsertRows();
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::preItemRemoved,
this,
[=](int index) {
beginRemoveRows(QModelIndex(), index, index);
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::postItemRemoved,
this,
[=]() {
endRemoveRows();
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::updateModel,
this,
[=](int index, QVector<int> roles) {
emit this->dataChanged(this->index(index), this->index(index), roles);
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::preListChanged,
this,
[=]() {
beginResetModel();
},
Qt::DirectConnection);
connect(
this->list,
&BaseList::postListChanged,
this,
[=]() {
endResetModel();
},
Qt::DirectConnection);
}
endResetModel();
}
void BaseModel::setList(BaseList *value)
{
value->modelHooked();
this->m_model->setList(value);
this->getList()->m_model = this;
emit this->listChanged();
}
BaseModel::PrivateAbstractListModel::PrivateAbstractListModel(BaseModel *model)
: QAbstractListModel(model)
, list(nullptr)
, m_model(model)
{
connect(
this,
&QAbstractListModel::rowsInserted,
this,
[this](QModelIndex, int, int) {
if (this->list) {
emit this->list->countChanged();
}
},
Qt::DirectConnection);
connect(
this,
&QAbstractListModel::rowsRemoved,
this,
[this](QModelIndex, int, int) {
if (this->list) {
emit this->list->countChanged();
}
},
Qt::DirectConnection);
}
int BaseModel::PrivateAbstractListModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid() || !list)
return 0;
return list->items().size();
}
QVariant BaseModel::PrivateAbstractListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || !list)
return QVariant();
auto value = list->items().at(index.row())[static_cast<FMH::MODEL_KEY>(role)];
if (role == FMH::MODEL_KEY::ADDDATE || role == FMH::MODEL_KEY::DATE || role == FMH::MODEL_KEY::MODIFIED || role == FMH::MODEL_KEY::RELEASEDATE) {
const auto date = QDateTime::fromString(value, Qt::TextDate);
if (date.isValid())
return date;
}
return value;
}
bool BaseModel::PrivateAbstractListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(index);
Q_UNUSED(value);
Q_UNUSED(role);
return false;
}
Qt::ItemFlags BaseModel::PrivateAbstractListModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsEditable; // FIXME: Implement me!
}
QHash<int, QByteArray> BaseModel::PrivateAbstractListModel::roleNames() const
{
QHash<int, QByteArray> names;
for (const auto &key : FMH::MODEL_NAME.keys())
names[key] = QString(FMH::MODEL_NAME[key]).toUtf8();
return names;
}

View file

@ -1,181 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 BASEMODEL_H
#define BASEMODEL_H
#include <QAbstractListModel>
#include <QList>
#include <QObject>
#include <QSortFilterProxyModel>
class BaseList;
/**
* @brief The BaseModel class
* The BaseModel is a template model to use with a BaseList, it aims to be a generic and simple data model to quickly model string based models using the FMH::MODEL_LIST and FMH::MODEL_KEY types.
*
* This type is exposed to QML to quickly create a modle that can be filtered, sorted and has another usefull functionalities.
*/
class BaseModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(BaseList *list READ getList WRITE setList NOTIFY listChanged)
Q_PROPERTY(QString filter READ getFilter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(Qt::SortOrder sortOrder READ getSortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
Q_PROPERTY(QString sort READ getSort WRITE setSort NOTIFY sortChanged)
public:
BaseModel(QObject *parent = nullptr);
/**
* @brief getList
* The list being handled by the model
* @return
*/
BaseList *getList() const;
/**
* @brief setList
* For the model to work you need to set a BaseList, by subclassing it and exposing it to the QML engine
* @param value
*/
void setList(BaseList *value);
/**
* @brief getSortOrder
* The current sort order being applied
* @return
*/
Qt::SortOrder getSortOrder() const;
/**
* @brief getSort
* The current sorting key
* @return
*/
QString getSort() const;
/**
* @brief getFilter
* The filter being applied to the model
* @return
*/
const QString getFilter() const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
private:
class PrivateAbstractListModel;
PrivateAbstractListModel *m_model;
QString m_filter;
Qt::SortOrder m_sortOrder;
QString m_sort;
[[deprecated]] void setFilterString(const QString &string);
[[deprecated]] void setSortOrder(const int &sortOrder);
public slots:
/**
* @brief setFilter
* Filter the model using a simple string, to clear the filter just set it to a empty string
* @param filter
* Simple filter string
*/
void setFilter(const QString &filter);
/**
* @brief setSortOrder
* Set the sort order, asc or dec
* @param sortOrder
*/
void setSortOrder(const Qt::SortOrder &sortOrder);
/**
* @brief setSort
* Set the sort key. The sort keys can be found in the FMH::MODEL_KEY keys
* @param sort
*/
void setSort(const QString &sort);
/**
* @brief get
* Returns an item in the model/list. This method correctly maps the given index in case the modle has been sorted or filtered
* @param index
* Index of the item in the list
* @return
*/
QVariantMap get(const int &index) const;
/**
* @brief getAll
* Returns all the items in the list represented as a QVariantList to be able to be used in QML. This operation performs a transformation from FMH::MODEL_LIST to QVariantList
* @return
* All the items in the list
*/
QVariantList getAll() const;
/**
* @brief mappedFromSource
* Maps an index from the base list to the model, incase the modle has been filtered or sorted, this gives you the right mapped index
* @param index
* @return
*/
int mappedFromSource(const int &index) const;
/**
* @brief mappedToSource
* given an index from the filtered or sorted model it return the mapped index to the original list index
* @param index
* @return
*/
int mappedToSource(const int &index) const;
signals:
void listChanged();
void filterChanged(QString filter);
void sortOrderChanged(Qt::SortOrder sortOrder);
void sortChanged(QString sort);
};
class BaseModel::PrivateAbstractListModel : public QAbstractListModel
{
Q_OBJECT
public:
PrivateAbstractListModel(BaseModel *model);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
// Editable:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual QHash<int, QByteArray> roleNames() const override;
BaseList *getList() const;
void setList(BaseList *value);
private:
BaseList *list;
BaseModel *m_model;
};
#endif // BASEMODEL_H

View file

@ -1,31 +0,0 @@
#ifndef DESKTOPVIEW_H
#define DESKTOPVIEW_H
#include <QQuickView>
class DesktopView : public QQuickView
{
Q_OBJECT
Q_PROPERTY(QRect screenRect READ screenRect NOTIFY screenRectChanged)
Q_PROPERTY(QRect screenAvailableRect READ screenAvailableRect NOTIFY screenAvailableGeometryChanged)
public:
explicit DesktopView(QQuickView *parent = nullptr);
QRect screenRect();
QRect screenAvailableRect();
signals:
void screenRectChanged();
void screenAvailableGeometryChanged();
private slots:
void onGeometryChanged();
void onAvailableGeometryChanged(const QRect &geometry);
private:
QRect m_screenRect;
QRect m_screenAvailableRect;
};
#endif // DESKTOPVIEW_H

View file

@ -1,239 +0,0 @@
/*
* Copyright 2018 Camilo Higuita <milo.h@aol.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "fm.h"
#include <QDateTime>
#include <QFileInfo>
#include <QLocale>
#include <QRegularExpression>
#include <QUrl>
#include <KCoreDirLister>
#include <KFileItem>
#include <KFilePlacesModel>
#include <KIO/CopyJob>
#include <KIO/DeleteJob>
#include <KIO/MkdirJob>
#include <KIO/SimpleJob>
#include <QIcon>
FM::FM(QObject *parent)
: QObject(parent)
#ifdef COMPONENT_SYNCING
, sync(new Syncing(this))
#endif
, dirLister(new KCoreDirLister(this))
{
this->dirLister->setAutoUpdate(true);
const static auto packItems = [](const KFileItemList &items) -> FMH::MODEL_LIST {
return std::accumulate(items.constBegin(), items.constEnd(), FMH::MODEL_LIST(), [](FMH::MODEL_LIST &res, const KFileItem &item) -> FMH::MODEL_LIST {
res << FMH::getFileInfo(item);
return res;
});
};
connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &)>(&KCoreDirLister::completed), this, [&](QUrl url) {
qDebug() << "PATH CONTENT READY" << url;
emit this->pathContentReady(url);
});
connect(dirLister, static_cast<void (KCoreDirLister::*)(const QUrl &, const KFileItemList &items)>(&KCoreDirLister::itemsAdded), this, [&](QUrl dirUrl, KFileItemList items) {
qDebug() << "MORE ITEMS WERE ADDED";
emit this->pathContentItemsReady({dirUrl, packItems(items)});
});
// connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::newItems), [&](KFileItemList items)
// {
// qDebug()<< "MORE NEW ITEMS WERE ADDED";
// for(const auto &item : items)
// qDebug()<< "MORE <<" << item.url();
//
// emit this->pathContentChanged(dirLister->url());
// });
connect(dirLister, static_cast<void (KCoreDirLister::*)(const KFileItemList &items)>(&KCoreDirLister::itemsDeleted), this, [&](KFileItemList items) {
qDebug() << "ITEMS WERE DELETED";
emit this->pathContentItemsRemoved({dirLister->url(), packItems(items)});
});
connect(dirLister, static_cast<void (KCoreDirLister::*)(const QList<QPair<KFileItem, KFileItem>> &items)>(&KCoreDirLister::refreshItems), this, [&](QList<QPair<KFileItem, KFileItem>> items) {
qDebug() << "ITEMS WERE REFRESHED";
const auto res = std::accumulate(
items.constBegin(), items.constEnd(), QVector<QPair<FMH::MODEL, FMH::MODEL>>(), [](QVector<QPair<FMH::MODEL, FMH::MODEL>> &list, const QPair<KFileItem, KFileItem> &pair) -> QVector<QPair<FMH::MODEL, FMH::MODEL>> {
list << QPair<FMH::MODEL, FMH::MODEL> {FMH::getFileInfo(pair.first), FMH::getFileInfo(pair.second)};
return list;
});
emit this->pathContentItemsChanged(res);
});
#ifdef COMPONENT_SYNCING
connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) {
emit this->cloudServerContentReady(list, url);
});
connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) {
switch (signalType) {
case Syncing::SIGNAL_TYPE::OPEN:
FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]);
break;
case Syncing::SIGNAL_TYPE::DOWNLOAD:
emit this->cloudItemReady(item, url);
break;
case Syncing::SIGNAL_TYPE::COPY: {
QVariantMap data;
const auto keys = item.keys();
for (auto key : keys)
data.insert(FMH::MODEL_NAME[key], item[key]);
// this->copy(QVariantList {data}, this->sync->getCopyTo());
break;
}
default:
return;
}
});
connect(this->sync, &Syncing::error, [this](const QString &message) {
emit this->warningMessage(message);
});
connect(this->sync, &Syncing::progress, [this](const int &percent) {
emit this->loadProgress(percent);
});
connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) {
emit this->newItem(dir, url);
});
connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) {
emit this->newItem(item, url);
});
#endif
}
void FM::getPathContent(const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters, const QDirIterator::IteratorFlags &iteratorFlags)
{
qDebug() << "Getting async path contents";
Q_UNUSED(iteratorFlags)
this->dirLister->setShowingDotFiles(hidden);
this->dirLister->setDirOnlyMode(onlyDirs);
this->dirLister->setNameFilter(filters.join(" "));
if (this->dirLister->openUrl(path))
qDebug() << "GETTING PATH CONTENT" << path;
}
FMH::MODEL_LIST FM::getAppsPath()
{
return FMH::MODEL_LIST {FMH::MODEL {{FMH::MODEL_KEY::ICON, "system-run"},
{FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]},
{FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]},
{FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]}}};
}
bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth)
{
#ifdef COMPONENT_SYNCING
const auto __list = path.toString().replace("cloud:///", "/").split("/");
if (__list.isEmpty() || __list.size() < 2) {
qWarning() << "Could not parse username to get cloud server content";
return false;
}
auto user = __list[1];
// auto data = this->get(QString("select * from clouds where user = '%1'").arg(user));
QVariantList data;
if (data.isEmpty())
return false;
auto map = data.first().toMap();
user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString();
auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString();
auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString();
this->sync->setCredentials(server, user, password);
this->sync->listContent(path, filters, depth);
return true;
#else
Q_UNUSED(path)
Q_UNUSED(filters)
Q_UNUSED(depth)
return false;
#endif
}
void FM::createCloudDir(const QString &path, const QString &name)
{
#ifdef COMPONENT_SYNCING
this->sync->createDir(path, name);
#endif
}
void FM::openCloudItem(const QVariantMap &item)
{
#ifdef COMPONENT_SYNCING
FMH::MODEL data;
const auto keys = item.keys();
for (const auto &key : keys)
data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString());
this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN);
#endif
}
void FM::getCloudItem(const QVariantMap &item)
{
#ifdef COMPONENT_SYNCING
this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD);
#endif
}
QString FM::resolveUserCloudCachePath(const QString &server, const QString &user)
{
Q_UNUSED(server)
return FMH::CloudCachePath + "opendesktop/" + user;
}
QString FM::resolveLocalCloudPath(const QString &path)
{
#ifdef COMPONENT_SYNCING
return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH] + this->sync->getUser(), "");
#else
return QString();
#endif
}
bool FM::cut(const QList<QUrl> &urls, const QUrl &where)
{
return FMStatic::cut(urls, where);
}
bool FM::copy(const QList<QUrl> &urls, const QUrl &where)
{
return FMStatic::copy(urls, where);
}

206
src/fm.h
View file

@ -1,206 +0,0 @@
#ifndef FM_H
#define FM_H
#include <QHash>
#include <QObject>
#include <QStorageInfo>
#include <QStringList>
#include <QVariantList>
#include <QVector>
#include "fmh.h"
#include "fmstatic.h"
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
class KCoreDirLister;
#else
class QFileSystemWatcher;
namespace FMH
{
class FileLoader;
}
/**
* @brief The QDirLister class
* Placeholder for the KCoreDirLister for other system other than GNU Linux
*/
class QDirLister : public QObject
{
Q_OBJECT
public:
explicit QDirLister(QObject *parent = nullptr);
public slots:
/**
* @brief openUrl
* @param url
* @return
*/
bool openUrl(const QUrl &url);
/**
* @brief setNameFilter
* @param filters
*/
void setNameFilter(QString filters);
/**
* @brief setDirOnlyMode
* @param value
*/
void setDirOnlyMode(bool value);
/**
* @brief setShowingDotFiles
* @param value
*/
void setShowingDotFiles(bool value);
signals:
void itemsReady(FMH::MODEL_LIST items, QUrl url);
void itemReady(FMH::MODEL item, QUrl url);
void completed(QUrl url);
void itemsAdded(FMH::MODEL_LIST items, QUrl url);
void itemsDeleted(FMH::MODEL_LIST items, QUrl url);
void newItems(FMH::MODEL_LIST items, QUrl url);
void refreshItems(QVector<QPair<FMH::MODEL, FMH::MODEL>> items, QUrl url);
private:
FMH::FileLoader *m_loader;
QFileSystemWatcher *m_watcher;
FMH::MODEL_LIST m_list;
QString m_nameFilters;
QUrl m_url;
bool m_dirOnly = false;
bool m_showDotFiles = false;
bool m_checking = false;
void reviewChanges();
bool includes(const QUrl &url);
int indexOf(const FMH::MODEL_KEY &key, const QString &value) const;
};
#endif
class Syncing;
class Tagging;
/**
* @brief The FM class
* File management methods with syncing and tagging integration if such components were enabled with COMPONENT_SYNCING and COMPONENT_TAGGING
*/
class FM : public QObject
{
Q_OBJECT
public:
FM(QObject *parent = nullptr);
/** Syncing **/
/**
* @brief getCloudServerContent
* Given a server URL address return the contents. This only works if the syncing component has been enabled COMPONENT_SYNCING
* @param server
* Server URL
* @param filters
* Filters to be applied
* @param depth
* How deep in the directory three go, for example 1 keeps the retrieval in the first level
* @return
*/
bool getCloudServerContent(const QUrl &server, const QStringList &filters = QStringList(), const int &depth = 0);
/**
* @brief createCloudDir
* Creates a directory in the server. This only works if the syncing component has been enabled COMPONENT_SYNCING
* @param path
* Server address URL
* @param name
* Directory name
*/
Q_INVOKABLE void createCloudDir(const QString &path, const QString &name);
/**
* @brief getPathContent
* Given a path URL extract the contents and return the information packaged as a model. This method is asyncronous and once items are ready signals are emitted, such as: pathContentItemsReady or pathContentReady
* @param path
* The directory path
* @param hidden
* If shoudl also pack hidden files
* @param onlyDirs
* Should only pack directories
* @param filters
* Filters to be applied to the retrieval
* @param iteratorFlags
* Directory iterator flags, for reference check QDirIterator documentation
*/
void getPathContent(const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags);
/**
* @brief resolveLocalCloudPath
* Given a server address URL resolve it to the local cache URL. This only works if the syncing component has been enabled COMPONENT_SYNCING
* @param path
* Server address
* @return
*/
QString resolveLocalCloudPath(const QString &path);
/**
* @brief getAppsPath
* Gives the path to the applications directory. Missing integration with other system other than GNU Linux
* @return
*/
static FMH::MODEL_LIST getAppsPath();
/**
* @brief resolveUserCloudCachePath
* @param server
* @param user
* @return
*/
static QString resolveUserCloudCachePath(const QString &server, const QString &user);
#ifdef COMPONENT_SYNCING
Syncing *sync;
#endif
private:
#ifdef COMPONENT_TAGGING
Tagging *tag;
#endif
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
KCoreDirLister *dirLister;
#else
QDirLister *dirLister;
#endif
signals:
void cloudServerContentReady(FMH::MODEL_LIST list, const QUrl &url);
void cloudItemReady(FMH::MODEL item, QUrl path); // when a item is downloaded and ready
void pathContentReady(QUrl path);
void pathContentItemsReady(FMH::PATH_CONTENT list);
void pathContentChanged(QUrl path);
void pathContentItemsChanged(QVector<QPair<FMH::MODEL, FMH::MODEL>> items);
void pathContentItemsRemoved(FMH::PATH_CONTENT list);
void warningMessage(QString message);
void loadProgress(int percent);
void dirCreated(FMH::MODEL dir);
void newItem(FMH::MODEL item, QUrl path); // when a new item is created
public slots:
void openCloudItem(const QVariantMap &item);
void getCloudItem(const QVariantMap &item);
/* ACTIONS */
bool copy(const QList<QUrl> &urls, const QUrl &where);
bool cut(const QList<QUrl> &urls, const QUrl &where);
friend class FMStatic;
};
#endif // FM_H

View file

@ -1,337 +0,0 @@
#include "fmh.h"
namespace FMH
{
const QVector<int> modelRoles(const FMH::MODEL &model)
{
const auto keys = model.keys();
return std::accumulate(keys.begin(), keys.end(), QVector<int>(), [](QVector<int> &res, const FMH::MODEL_KEY &key) {
res.append(key);
return res;
});
}
const QString mapValue(const QVariantMap &map, const FMH::MODEL_KEY &key)
{
return map[FMH::MODEL_NAME[key]].toString();
}
const QVariantMap toMap(const FMH::MODEL &model)
{
QVariantMap map;
for (const auto &key : model.keys())
map.insert(FMH::MODEL_NAME[key], model[key]);
return map;
}
const FMH::MODEL toModel(const QVariantMap &map)
{
FMH::MODEL model;
for (const auto &key : map.keys())
model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString());
return model;
}
const FMH::MODEL_LIST toModelList(const QVariantList &list)
{
FMH::MODEL_LIST res;
return std::accumulate(list.constBegin(), list.constEnd(), res, [](FMH::MODEL_LIST &res, const QVariant &item) -> FMH::MODEL_LIST {
res << FMH::toModel(item.toMap());
return res;
});
}
const QVariantList toMapList(const FMH::MODEL_LIST &list)
{
QVariantList res;
return std::accumulate(list.constBegin(), list.constEnd(), res, [](QVariantList &res, const FMH::MODEL &item) -> QVariantList {
res << FMH::toMap(item);
return res;
});
}
const FMH::MODEL filterModel(const FMH::MODEL &model, const QVector<FMH::MODEL_KEY> &keys)
{
FMH::MODEL res;
return std::accumulate(keys.constBegin(), keys.constEnd(), res, [=](FMH::MODEL &res, const FMH::MODEL_KEY &key) -> FMH::MODEL {
if (model.contains(key))
res[key] = model[key];
return res;
});
}
const QStringList modelToList(const FMH::MODEL_LIST &list, const FMH::MODEL_KEY &key)
{
QStringList res;
return std::accumulate(list.constBegin(), list.constEnd(), res, [key](QStringList &res, const FMH::MODEL &item) -> QStringList {
if (item.contains(key))
res << item[key];
return res;
});
}
bool fileExists(const QUrl &path)
{
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file" << path;
return false;
}
return QFileInfo::exists(path.toLocalFile());
}
const QString fileDir(const QUrl &path) // the directory path of the file
{
QString res = path.toString();
if (path.isLocalFile()) {
const QFileInfo file(path.toLocalFile());
if (file.isDir())
res = path.toString();
else
res = QUrl::fromLocalFile(file.dir().absolutePath()).toString();
} else
qWarning() << "The path is not a local one. FM::fileDir";
return res;
}
const QUrl parentDir(const QUrl &path)
{
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file, FM::parentDir" << path;
return path;
}
QDir dir(path.toLocalFile());
dir.cdUp();
return QUrl::fromLocalFile(dir.absolutePath());
}
const QVariantMap dirConf(const QUrl &path)
{
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file" << path;
return QVariantMap();
}
if (!fileExists(path))
return QVariantMap();
QString icon, iconsize, hidden, detailview, showthumbnail, showterminal;
uint count = 0, sortby = MODEL_KEY::MODIFIED, viewType = 0;
bool foldersFirst = false;
#if defined Q_OS_ANDROID || defined Q_OS_WIN || defined Q_OS_MACOS || defined Q_OS_IOS
QSettings file(path.toLocalFile(), QSettings::Format::NativeFormat);
file.beginGroup(QString("Desktop Entry"));
icon = file.value("Icon").toString();
file.endGroup();
file.beginGroup(QString("Settings"));
hidden = file.value("HiddenFilesShown").toString();
file.endGroup();
file.beginGroup(QString("MAUIFM"));
iconsize = file.value("IconSize").toString();
detailview = file.value("DetailView").toString();
showthumbnail = file.value("ShowThumbnail").toString();
showterminal = file.value("ShowTerminal").toString();
count = file.value("Count").toInt();
sortby = file.value("SortBy").toInt();
foldersFirst = file.value("FoldersFirst").toBool();
viewType = file.value("ViewType").toInt();
file.endGroup();
#else
KConfig file(path.toLocalFile());
icon = file.entryMap(QString("Desktop Entry"))["Icon"];
hidden = file.entryMap(QString("Settings"))["HiddenFilesShown"];
iconsize = file.entryMap(QString("MAUIFM"))["IconSize"];
detailview = file.entryMap(QString("MAUIFM"))["DetailView"];
showthumbnail = file.entryMap(QString("MAUIFM"))["ShowThumbnail"];
showterminal = file.entryMap(QString("MAUIFM"))["ShowTerminal"];
count = file.entryMap(QString("MAUIFM"))["Count"].toInt();
sortby = file.entryMap(QString("MAUIFM"))["SortBy"].toInt();
foldersFirst = file.entryMap(QString("MAUIFM"))["FoldersFirst"] == "true" ? true : false;
viewType = file.entryMap(QString("MAUIFM"))["ViewType"].toInt();
#endif
return QVariantMap({{MODEL_NAME[MODEL_KEY::ICON], icon.isEmpty() ? "folder" : icon},
{MODEL_NAME[MODEL_KEY::ICONSIZE], iconsize},
{MODEL_NAME[MODEL_KEY::COUNT], count},
{MODEL_NAME[MODEL_KEY::SHOWTERMINAL], showterminal.isEmpty() ? "false" : showterminal},
{MODEL_NAME[MODEL_KEY::SHOWTHUMBNAIL], showthumbnail.isEmpty() ? "false" : showthumbnail},
{MODEL_NAME[MODEL_KEY::DETAILVIEW], detailview.isEmpty() ? "false" : detailview},
{MODEL_NAME[MODEL_KEY::HIDDEN], hidden.isEmpty() ? false : (hidden == "true" ? true : false)},
{MODEL_NAME[MODEL_KEY::SORTBY], sortby},
{MODEL_NAME[MODEL_KEY::FOLDERSFIRST], foldersFirst},
{MODEL_NAME[MODEL_KEY::VIEWTYPE], viewType}});
}
void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value)
{
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file" << path;
return;
}
#if defined Q_OS_ANDROID || defined Q_OS_WIN || defined Q_OS_MACOS || defined Q_OS_IOS
QSettings file(path.toLocalFile(), QSettings::Format::IniFormat);
file.beginGroup(group);
file.setValue(key, value);
file.endGroup();
file.sync();
#else
KConfig file(path.toLocalFile(), KConfig::SimpleConfig);
auto kgroup = file.group(group);
kgroup.writeEntry(key, value);
// file.reparseConfiguration();
file.sync();
#endif
}
const QString getIconName(const QUrl &path)
{
if (path.isLocalFile() && QFileInfo(path.toLocalFile()).isDir()) {
if (folderIcon.contains(path.toString()))
return folderIcon[path.toString()];
else {
const auto icon = dirConf(QString(path.toString() + "/%1").arg(".directory"))[MODEL_NAME[MODEL_KEY::ICON]].toString();
return icon.isEmpty() ? "folder" : icon;
}
} else {
QMimeDatabase mime;
const auto type = mime.mimeTypeForFile(path.toString());
return type.iconName();
// KFileItem mime(path);
// return mime.iconName();
}
}
const QString getMime(const QUrl &path)
{
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file, getMime" << path;
return QString();
}
const QMimeDatabase mimedb;
return mimedb.mimeTypeForFile(path.toLocalFile()).name();
}
const QUrl thumbnailUrl(const QUrl &url, const QString &mimetype)
{
#if defined Q_OS_LINUX && !defined Q_OS_ANDROID
if (checkFileType(FILTER_TYPE::DOCUMENT, mimetype) || checkFileType(FILTER_TYPE::VIDEO, mimetype)) {
return QUrl("image://thumbnailer/" + url.toString());
}
#endif
if (checkFileType(FILTER_TYPE::IMAGE, mimetype)) {
return url;
}
return QUrl();
}
#if (!defined Q_OS_ANDROID && defined Q_OS_LINUX) || defined Q_OS_WIN
const FMH::MODEL getFileInfo(const KFileItem &kfile)
{
return MODEL {{MODEL_KEY::LABEL, kfile.name()},
{MODEL_KEY::NAME, kfile.name().remove(kfile.name().lastIndexOf("."), kfile.name().size())},
{MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)},
{MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)},
{MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)},
{MODEL_KEY::PATH, kfile.mostLocalUrl().toString()},
{MODEL_KEY::URL, kfile.mostLocalUrl().toString()},
{MODEL_KEY::THUMBNAIL, thumbnailUrl(kfile.mostLocalUrl(), kfile.mimetype()).toString()},
{MODEL_KEY::SYMLINK, kfile.linkDest()},
{MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()},
{MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()},
{MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()},
{MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()},
{MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()},
{MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()},
{MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()},
{MODEL_KEY::MIME, kfile.mimetype()},
{MODEL_KEY::GROUP, kfile.group()},
{MODEL_KEY::ICON, kfile.iconName()},
// for set wallpaper.
{MODEL_KEY::IMG, QVariant(kfile.mimetype().startsWith("image/")).toString()},
{MODEL_KEY::SIZE, QString::number(kfile.size())},
{MODEL_KEY::OWNER, kfile.user()},
{MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count()) : "0"}};
}
#endif
const FMH::MODEL getFileInfoModel(const QUrl &path)
{
MODEL res;
#if defined Q_OS_ANDROID || defined Q_OS_MACOS || defined Q_OS_IOS || defined Q_OS_WIN
const QFileInfo file(path.toLocalFile());
if (!file.exists())
return MODEL();
const auto mime = getMime(path);
res = MODEL {{MODEL_KEY::GROUP, file.group()},
{MODEL_KEY::OWNER, file.owner()},
{MODEL_KEY::SUFFIX, file.completeSuffix()},
{MODEL_KEY::LABEL, /*file.isDir() ? file.baseName() :*/ path == HomePath ? QStringLiteral("Home") : file.fileName()},
{MODEL_KEY::NAME, file.fileName()},
{MODEL_KEY::DATE, file.birthTime().toString(Qt::TextDate)},
{MODEL_KEY::MODIFIED, file.lastModified().toString(Qt::TextDate)},
{MODEL_KEY::LAST_READ, file.lastRead().toString(Qt::TextDate)},
{MODEL_KEY::MIME, mime},
{MODEL_KEY::SYMLINK, file.symLinkTarget()},
{MODEL_KEY::IS_SYMLINK, QVariant(file.isSymLink()).toString()},
{MODEL_KEY::IS_FILE, QVariant(file.isFile()).toString()},
{MODEL_KEY::HIDDEN, QVariant(file.isHidden()).toString()},
{MODEL_KEY::IS_DIR, QVariant(file.isDir()).toString()},
{MODEL_KEY::WRITABLE, QVariant(file.isWritable()).toString()},
{MODEL_KEY::READABLE, QVariant(file.isReadable()).toString()},
{MODEL_KEY::EXECUTABLE, QVariant(file.suffix().endsWith(".desktop")).toString()},
{MODEL_KEY::ICON, getIconName(path)},
{MODEL_KEY::SIZE, QString::number(file.size()) /*locale.formattedDataSize(file.size())*/},
{MODEL_KEY::PATH, path.toString()},
{MODEL_KEY::URL, path.toString()},
{MODEL_KEY::THUMBNAIL, thumbnailUrl(path, mime).toString()},
{MODEL_KEY::COUNT, file.isDir() ? QString::number(QDir(path.toLocalFile()).count()) : "0"}};
#else
res = getFileInfo(KFileItem(path, KFileItem::MimeTypeDetermination::NormalMimeTypeDetermination));
#endif
return res;
}
const QVariantMap getFileInfo(const QUrl &path)
{
return toMap(getFileInfoModel(path));
}
const MODEL getDirInfoModel(const QUrl &path, const QString &type)
{
auto res = getFileInfoModel(path);
res[MODEL_KEY::TYPE] = type;
return res;
}
const QVariantMap getDirInfo(const QUrl &path)
{
return toMap(getDirInfoModel(path));
}
PATHTYPE_KEY getPathType(const QUrl &url)
{
return PATHTYPE_SCHEME_NAME[url.scheme()];
}
bool checkFileType(const FMH::FILTER_TYPE &type, const QString &mimeTypeName)
{
return SUPPORTED_MIMETYPES[type].contains(mimeTypeName);
}
}

1019
src/fmh.h

File diff suppressed because it is too large Load diff

View file

@ -1,626 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2018 camilo higuita <milo.h@aol.com>
*
* 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 "fmlist.h"
#include "fm.h"
#if defined Q_OS_LINUX && !defined Q_OS_ANDROID
#include <KIO/EmptyTrashJob>
#endif
#include <QFuture>
#include <QObject>
#include <QThread>
#include <QtConcurrent/QtConcurrentRun>
#include <QtConcurrent>
FMList::FMList(QObject *parent)
: BaseList(parent)
, fm(new FM(this))
{
qRegisterMetaType<FMList *>("const FMList*"); // this is needed for QML to know of FMList in the search method
connect(this->fm, &FM::cloudServerContentReady, [&](const FMH::MODEL_LIST &list, const QUrl &url) {
if (this->path == url) {
this->assignList(list);
}
});
connect(this->fm, &FM::pathContentReady, [&](QUrl) {
emit this->preListChanged();
this->sortList();
this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "", this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true});
emit this->postListChanged();
});
connect(this->fm, &FM::pathContentItemsChanged, [&](QVector<QPair<FMH::MODEL, FMH::MODEL>> res) {
for (const auto &item : qAsConst(res)) {
const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item.first[FMH::MODEL_KEY::PATH]);
if (index >= this->list.size() || index < 0)
return;
this->list[index] = item.second;
emit this->updateModel(index, FMH::modelRoles(item.second));
}
});
connect(this->fm, &FM::pathContentItemsReady, [&](FMH::PATH_CONTENT res) {
if (res.path != this->path)
return;
this->appendToList(res.content);
});
connect(this->fm, &FM::pathContentItemsRemoved, [&](FMH::PATH_CONTENT res) {
if (res.path != this->path)
return;
if (!FMH::fileExists(res.path)) {
this->setStatus({STATUS_CODE::ERROR, "Error", "This URL cannot be listed", "documentinfo", true, false});
return;
}
for (const auto &item : qAsConst(res.content)) {
const auto index = this->indexOf(FMH::MODEL_KEY::PATH, item[FMH::MODEL_KEY::PATH]);
qDebug() << "SUPOSSED TO REMOVED THIS FORM THE LIST" << index << this->list.count() << item[FMH::MODEL_KEY::PATH];
this->remove(index);
}
this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "", this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true});
});
connect(this->fm, &FM::warningMessage, [&](const QString &message) {
emit this->warning(message);
});
connect(this->fm, &FM::loadProgress, [&](const int &percent) {
emit this->progress(percent);
});
connect(this->fm, &FM::pathContentChanged, [&](const QUrl &path) {
qDebug() << "FOLDER PATH CHANGED" << path;
if (path != this->path)
return;
this->sortList();
});
connect(this->fm, &FM::newItem, [&](const FMH::MODEL &item, const QUrl &url) {
if (this->path == url) {
emit this->preItemAppended();
this->list << item;
emit this->postItemAppended();
}
});
}
void FMList::assignList(const FMH::MODEL_LIST &list)
{
emit this->preListChanged();
this->list = list;
this->sortList();
this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "", this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true});
emit this->postListChanged();
}
void FMList::appendToList(const FMH::MODEL_LIST &list)
{
emit this->preItemsAppended(list.size());
this->list << list;
emit this->postItemAppended();
}
void FMList::clear()
{
emit this->preListChanged();
this->list.clear();
emit this->postListChanged();
}
void FMList::setList()
{
qDebug() << "PATHTYPE FOR URL" << pathType << this->path.toString() << this->filters << this;
this->clear();
switch (this->pathType) {
case FMList::PATHTYPE::CLOUD_PATH:
this->fm->getCloudServerContent(this->path.toString(), this->filters, this->cloudDepth);
break; // ASYNC
default: {
const bool exists = this->path.isLocalFile() ? FMH::fileExists(this->path) : true;
if (!exists)
this->setStatus({STATUS_CODE::ERROR, "Error", "This URL cannot be listed", "documentinfo", this->list.isEmpty(), exists});
else {
this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, QStringList() << this->filters << FMH::FILTER_LIST[static_cast<FMH::FILTER_TYPE>(this->filterType)]);
}
break; // ASYNC
}
}
}
void FMList::reset()
{
this->setList();
}
const FMH::MODEL_LIST &FMList::items() const
{
return this->list;
}
FMList::SORTBY FMList::getSortBy() const
{
return this->sort;
}
void FMList::setSortBy(const FMList::SORTBY &key)
{
if (this->sort == key)
return;
emit this->preListChanged();
this->sort = key;
this->sortList();
emit this->sortByChanged();
emit this->postListChanged();
}
void FMList::sortList()
{
const FMH::MODEL_KEY key = static_cast<FMH::MODEL_KEY>(this->sort);
auto index = 0;
if (this->foldersFirst) {
qSort(this->list.begin(), this->list.end(), [](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool {
Q_UNUSED(e2)
const auto key = FMH::MODEL_KEY::MIME;
return e1[key] == "inode/directory";
});
for (const auto &item : qAsConst(this->list))
if (item[FMH::MODEL_KEY::MIME] == "inode/directory")
index++;
else
break;
std::sort(this->list.begin(), this->list.begin() + index, [&key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool {
switch (key) {
case FMH::MODEL_KEY::SIZE: {
if (e1[key].toDouble() > e2[key].toDouble())
return true;
break;
}
case FMH::MODEL_KEY::MODIFIED:
case FMH::MODEL_KEY::DATE: {
auto currentTime = QDateTime::currentDateTime();
auto date1 = QDateTime::fromString(e1[key], Qt::TextDate);
auto date2 = QDateTime::fromString(e2[key], Qt::TextDate);
if (date1.secsTo(currentTime) < date2.secsTo(currentTime))
return true;
break;
}
case FMH::MODEL_KEY::LABEL: {
const auto str1 = QString(e1[key]).toLower();
const auto str2 = QString(e2[key]).toLower();
if (str1 < str2)
return true;
break;
}
default:
if (e1[key] < e2[key])
return true;
}
return false;
});
}
std::sort(this->list.begin() + index, this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool {
switch (key) {
case FMH::MODEL_KEY::MIME:
if (e1[key] == "inode/directory")
return true;
break;
case FMH::MODEL_KEY::SIZE: {
if (e1[key].toDouble() > e2[key].toDouble())
return true;
break;
}
case FMH::MODEL_KEY::MODIFIED:
case FMH::MODEL_KEY::DATE: {
auto currentTime = QDateTime::currentDateTime();
auto date1 = QDateTime::fromString(e1[key], Qt::TextDate);
auto date2 = QDateTime::fromString(e2[key], Qt::TextDate);
if (date1.secsTo(currentTime) < date2.secsTo(currentTime))
return true;
break;
}
case FMH::MODEL_KEY::LABEL: {
const auto str1 = QString(e1[key]).toLower();
const auto str2 = QString(e2[key]).toLower();
if (str1 < str2)
return true;
break;
}
default:
if (e1[key] < e2[key])
return true;
}
return false;
});
}
QString FMList::getPathName() const
{
return this->pathName;
}
QUrl FMList::getPath() const
{
return this->path;
}
void FMList::setPath(const QUrl &path)
{
QUrl path_ = QUrl::fromUserInput(path.toString().trimmed());
if (this->path == path_)
return;
this->path = path_;
m_navHistory.appendPath(this->path);
this->setStatus({STATUS_CODE::LOADING, "Loading content", "Almost ready!", "view-refresh", true, false});
const auto __scheme = this->path.scheme();
this->pathName = QDir(this->path.toLocalFile()).dirName();
if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]) {
this->pathType = FMList::PATHTYPE::CLOUD_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::APPS_PATH]) {
this->pathType = FMList::PATHTYPE::APPS_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TAGS_PATH]) {
this->pathType = FMList::PATHTYPE::TAGS_PATH;
this->pathName = this->path.path();
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TRASH_PATH]) {
this->pathType = FMList::PATHTYPE::TRASH_PATH;
this->pathName = "Trash";
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH]) {
this->pathType = FMList::PATHTYPE::PLACES_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::MTP_PATH]) {
this->pathType = FMList::PATHTYPE::MTP_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::FISH_PATH]) {
this->pathType = FMList::PATHTYPE::FISH_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::REMOTE_PATH]) {
this->pathType = FMList::PATHTYPE::REMOTE_PATH;
} else if (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::DRIVES_PATH]) {
this->pathType = FMList::PATHTYPE::DRIVES_PATH;
} else {
this->pathType = FMList::PATHTYPE::OTHER_PATH;
}
emit this->pathNameChanged();
emit this->pathTypeChanged();
emit this->pathChanged();
}
FMList::PATHTYPE FMList::getPathType() const
{
return this->pathType;
}
QStringList FMList::getFilters() const
{
return this->filters;
}
void FMList::setFilters(const QStringList &filters)
{
if (this->filters == filters)
return;
this->filters = filters;
emit this->filtersChanged();
}
FMList::FILTER FMList::getFilterType() const
{
return this->filterType;
}
void FMList::setFilterType(const FMList::FILTER &type)
{
if (this->filterType == type)
return;
this->filterType = type;
emit this->filterTypeChanged();
}
bool FMList::getHidden() const
{
return this->hidden;
}
void FMList::setHidden(const bool &state)
{
if (this->hidden == state)
return;
this->hidden = state;
emit this->hiddenChanged();
}
bool FMList::getOnlyDirs() const
{
return this->onlyDirs;
}
void FMList::setOnlyDirs(const bool &state)
{
if (this->onlyDirs == state)
return;
this->onlyDirs = state;
emit this->onlyDirsChanged();
}
void FMList::refresh()
{
emit this->pathChanged();
}
void FMList::createDir(const QString &name)
{
if (this->pathType == FMList::PATHTYPE::CLOUD_PATH) {
#ifdef COMPONENT_SYNCING
this->fm->createCloudDir(QString(this->path.toString()).replace(FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH] + "/" + this->fm->sync->getUser(), ""), name);
#endif
} else {
FMStatic::createDir(this->path, name);
}
}
void FMList::copyInto(const QStringList &urls)
{
this->fm->copy(QUrl::fromStringList(urls), this->path);
}
void FMList::cutInto(const QStringList &urls)
{
this->fm->cut(QUrl::fromStringList(urls), this->path);
// else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH)
// {
// this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_NAME[FMList::PATHTYPE::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name);
// }
}
void FMList::setDirIcon(const int &index, const QString &iconName)
{
if (index >= this->list.size() || index < 0)
return;
// const auto index_ = this->mappedIndex(index);
const auto path = QUrl(this->list.at(index)[FMH::MODEL_KEY::PATH]);
if (!FMStatic::isDir(path))
return;
FMH::setDirConf(path.toString() + "/.directory", "Desktop Entry", "Icon", iconName);
this->list[index][FMH::MODEL_KEY::ICON] = iconName;
emit this->updateModel(index, QVector<int> {FMH::MODEL_KEY::ICON});
}
const QUrl FMList::getParentPath()
{
switch (this->pathType) {
case FMList::PATHTYPE::PLACES_PATH:
return FMStatic::parentDir(this->path).toString();
default:
return this->previousPath();
}
}
const QUrl FMList::posteriorPath()
{
const auto url = m_navHistory.getPosteriorPath();
if (url.isEmpty())
return this->path;
return url;
}
const QUrl FMList::previousPath()
{
const auto url = m_navHistory.getPreviousPath();
if (url.isEmpty())
return this->path;
return url;
}
bool FMList::getFoldersFirst() const
{
return this->foldersFirst;
}
void FMList::setFoldersFirst(const bool &value)
{
if (this->foldersFirst == value)
return;
emit this->preListChanged();
this->foldersFirst = value;
emit this->foldersFirstChanged();
this->sortList();
emit this->postListChanged();
}
void FMList::search(const QString &query, const FMList *currentFMList)
{
this->search(query, currentFMList->getPath(), currentFMList->getHidden(), currentFMList->getOnlyDirs(), currentFMList->getFilters());
}
void FMList::componentComplete()
{
connect(this, &FMList::pathChanged, this, &FMList::setList);
connect(this, &FMList::filtersChanged, this, &FMList::setList);
connect(this, &FMList::filterTypeChanged, this, &FMList::setList);
connect(this, &FMList::hiddenChanged, this, &FMList::setList);
connect(this, &FMList::onlyDirsChanged, this, &FMList::setList);
this->setList();
}
void FMList::search(const QString &query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters)
{
qDebug() << "SEARCHING FOR" << query << path;
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file. So search will only filter the content" << path;
this->filterContent(query, path);
return;
}
QFutureWatcher<FMH::PATH_CONTENT> *watcher = new QFutureWatcher<FMH::PATH_CONTENT>;
connect(watcher, &QFutureWatcher<FMH::MODEL_LIST>::finished, [=]() {
const auto res = watcher->future().result();
this->assignList(res.content);
emit this->searchResultReady();
watcher->deleteLater();
});
QFuture<FMH::PATH_CONTENT> t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT {
FMH::PATH_CONTENT res;
res.path = path.toString();
res.content = FMStatic::search(query, path, hidden, onlyDirs, filters);
return res;
});
watcher->setFuture(t1);
}
void FMList::filterContent(const QString &query, const QUrl &path)
{
if (this->list.isEmpty()) {
qDebug() << "Can not filter content. List is empty";
return;
}
QFutureWatcher<FMH::PATH_CONTENT> *watcher = new QFutureWatcher<FMH::PATH_CONTENT>;
connect(watcher, &QFutureWatcher<FMH::MODEL_LIST>::finished, [=]() {
const auto res = watcher->future().result();
this->assignList(res.content);
emit this->searchResultReady();
watcher->deleteLater();
});
QFuture<FMH::PATH_CONTENT> t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT {
FMH::MODEL_LIST m_content;
FMH::PATH_CONTENT res;
for (const auto &item : qAsConst(this->list)) {
if (item[FMH::MODEL_KEY::LABEL].contains(query, Qt::CaseInsensitive) || item[FMH::MODEL_KEY::SUFFIX].contains(query, Qt::CaseInsensitive) || item[FMH::MODEL_KEY::MIME].contains(query, Qt::CaseInsensitive)) {
m_content << item;
}
}
res.path = path.toString();
res.content = m_content;
return res;
});
watcher->setFuture(t1);
}
int FMList::getCloudDepth() const
{
return this->cloudDepth;
}
void FMList::setCloudDepth(const int &value)
{
if (this->cloudDepth == value)
return;
this->cloudDepth = value;
emit this->cloudDepthChanged();
}
PathStatus FMList::getStatus() const
{
return this->m_status;
}
void FMList::setStatus(const PathStatus &status)
{
this->m_status = status;
emit this->statusChanged();
}
void FMList::remove(const int &index)
{
if (index >= this->list.size() || index < 0)
return;
emit this->preItemRemoved(index);
this->list.remove(index);
emit this->postItemRemoved();
}

View file

@ -1,450 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2018 Camilo Higuita <email>
*
* 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 FMLIST_H
#define FMLIST_H
#include "fmh.h"
#include "baselist.h"
#include <QObject>
class FM;
enum STATUS_CODE : uint_fast8_t { LOADING, ERROR, READY };
/**
* @brief The PathStatus class
* Represents the status of a directory, be it non existance, loading or empty.
*/
class PathStatus
{
Q_GADGET
Q_PROPERTY(STATUS_CODE code MEMBER m_code)
Q_PROPERTY(QString title MEMBER m_title)
Q_PROPERTY(QString message MEMBER m_message)
Q_PROPERTY(QString icon MEMBER m_icon)
Q_PROPERTY(bool empty MEMBER m_empty)
Q_PROPERTY(bool exists MEMBER m_exists)
public:
STATUS_CODE m_code;
QString m_title;
QString m_message;
QString m_icon;
bool m_empty = false;
bool m_exists = false;
};
Q_DECLARE_METATYPE(PathStatus)
struct NavHistory {
void appendPath(const QUrl &path)
{
this->prev_history.append(path);
}
QUrl getPosteriorPath()
{
if (this->post_history.isEmpty())
return QUrl();
return this->post_history.takeLast();
}
QUrl getPreviousPath()
{
if (this->prev_history.isEmpty())
return QUrl();
if (this->prev_history.length() < 2)
return this->prev_history.at(0);
this->post_history.append(this->prev_history.takeLast());
return this->prev_history.takeLast();
}
private:
QVector<QUrl> prev_history;
QVector<QUrl> post_history;
};
/**
* @brief The FMList class
* Model for listing the file system files and directories and perfom relevant actions upon it
*/
class FMList : public BaseList
{
Q_OBJECT
// writable
Q_PROPERTY(QUrl path READ getPath WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(bool hidden READ getHidden WRITE setHidden NOTIFY hiddenChanged)
Q_PROPERTY(bool onlyDirs READ getOnlyDirs WRITE setOnlyDirs NOTIFY onlyDirsChanged)
Q_PROPERTY(bool foldersFirst READ getFoldersFirst WRITE setFoldersFirst NOTIFY foldersFirstChanged)
Q_PROPERTY(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged)
Q_PROPERTY(QStringList filters READ getFilters WRITE setFilters NOTIFY filtersChanged)
Q_PROPERTY(FMList::FILTER filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged)
Q_PROPERTY(FMList::SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged)
// readonly
Q_PROPERTY(QString pathName READ getPathName NOTIFY pathNameChanged FINAL)
Q_PROPERTY(FMList::PATHTYPE pathType READ getPathType NOTIFY pathTypeChanged FINAL)
Q_PROPERTY(PathStatus status READ getStatus NOTIFY statusChanged FINAL)
Q_PROPERTY(QUrl parentPath READ getParentPath NOTIFY pathChanged)
public:
enum SORTBY : uint_fast8_t {
SIZE = FMH::MODEL_KEY::SIZE,
MODIFIED = FMH::MODEL_KEY::MODIFIED,
DATE = FMH::MODEL_KEY::DATE,
LABEL = FMH::MODEL_KEY::LABEL,
MIME = FMH::MODEL_KEY::MIME,
ADDDATE = FMH::MODEL_KEY::MIME,
TITLE = FMH::MODEL_KEY::TITLE,
PLACE = FMH::MODEL_KEY::PLACE,
FORMAT = FMH::MODEL_KEY::FORMAT
};
Q_ENUM(SORTBY)
enum FILTER : uint_fast8_t {
AUDIO = FMH::FILTER_TYPE::AUDIO,
VIDEO = FMH::FILTER_TYPE::VIDEO,
TEXT = FMH::FILTER_TYPE::TEXT,
IMAGE = FMH::FILTER_TYPE::IMAGE,
DOCUMENT = FMH::FILTER_TYPE::DOCUMENT,
COMPRESSED = FMH::FILTER_TYPE::COMPRESSED,
FONT = FMH::FILTER_TYPE::FONT,
NONE = FMH::FILTER_TYPE::NONE
};
Q_ENUM(FILTER)
enum PATHTYPE : uint_fast8_t {
PLACES_PATH = FMH::PATHTYPE_KEY::PLACES_PATH,
FISH_PATH = FMH::PATHTYPE_KEY::FISH_PATH,
MTP_PATH = FMH::PATHTYPE_KEY::MTP_PATH,
REMOTE_PATH = FMH::PATHTYPE_KEY::REMOTE_PATH,
DRIVES_PATH = FMH::PATHTYPE_KEY::DRIVES_PATH,
REMOVABLE_PATH = FMH::PATHTYPE_KEY::REMOVABLE_PATH,
TAGS_PATH = FMH::PATHTYPE_KEY::TAGS_PATH,
APPS_PATH = FMH::PATHTYPE_KEY::APPS_PATH,
TRASH_PATH = FMH::PATHTYPE_KEY::TRASH_PATH,
CLOUD_PATH = FMH::PATHTYPE_KEY::CLOUD_PATH,
QUICK_PATH = FMH::PATHTYPE_KEY::QUICK_PATH,
OTHER_PATH = FMH::PATHTYPE_KEY::OTHER_PATH
};
Q_ENUM(PATHTYPE)
enum VIEW_TYPE : uint_fast8_t {
ICON_VIEW,
LIST_VIEW,
MILLERS_VIEW
};
Q_ENUM(VIEW_TYPE)
Q_ENUM(STATUS_CODE)
/**
* @brief FMList
* @param parent
*/
FMList(QObject *parent = nullptr);
/**
* @brief items
* @return
*/
const FMH::MODEL_LIST &items() const final override;
/**
* @brief getSortBy
* @return
*/
FMList::SORTBY getSortBy() const;
/**
* @brief setSortBy
* @param key
*/
void setSortBy(const FMList::SORTBY &key);
/**
* @brief componentComplete
*/
void componentComplete() override final;
/**
* @brief getPath
* Current path being watched and model
* @return
* Directory URL
*/
QUrl getPath() const;
/**
* @brief setPath
* Set the directory path to be model
* @param path
* Directory URL
*/
void setPath(const QUrl &path);
/**
* @brief getPathName
* The short name of the current directory
* @return
*/
QString getPathName() const;
/**
* @brief getPathType
* The type of the current path, be it LOCAl, TAGS, CLOUD, APPS, DEVICE or others
* @return
* Path type value
*/
FMList::PATHTYPE getPathType() const;
/**
* @brief getFilters
* The filters being applied to the current directory
* @return
* List of filters
*/
QStringList getFilters() const;
/**
* @brief setFilters
* FIlters to be applied as regular expressions
* @param filters
*/
void setFilters(const QStringList &filters);
/**
* @brief getFilterType
* Filter typebeing applied, for example, filtering by AUDIO or IMAGES etc...
* @return
*/
FMList::FILTER getFilterType() const;
/**
* @brief setFilterType
* Apply a filter type, this a quick shortcut for applying a filter on a file type such as AUDIO, IMAGE, DOCUMENT
* @param type
*/
void setFilterType(const FMList::FILTER &type);
/**
* @brief getHidden
* Returns if the current model is including hidden files
* @return
*/
bool getHidden() const;
/**
* @brief setHidden
* List hidden files in the model
* @param state
*/
void setHidden(const bool &state);
/**
* @brief getOnlyDirs
* Returns if the current model is including only directories or not
* @return
*/
bool getOnlyDirs() const;
/**
* @brief setOnlyDirs
* Only list directories when modeling a directory
* @param state
*/
void setOnlyDirs(const bool &state);
/**
* @brief getParentPath
* Returns a URL to the parent directory of the current directory being modeled or the previous directory if the current URL is not a local file
* @return
*/
const QUrl getParentPath();
/**
* @brief getFoldersFirst
* Returns whether directories are listed first before other files
* @return
*/
bool getFoldersFirst() const;
/**
* @brief setFoldersFirst
* List directories first
* @param value
*/
void setFoldersFirst(const bool &value);
/**
* @brief getCloudDepth
* @return
*/
int getCloudDepth() const;
/**
* @brief setCloudDepth
* @param value
*/
void setCloudDepth(const int &value);
/**
* @brief getStatus
* Get the current status of the current path
* @return
*/
PathStatus getStatus() const;
private:
FM *fm;
void clear();
void reset();
void setList();
void assignList(const FMH::MODEL_LIST &list);
void appendToList(const FMH::MODEL_LIST &list);
void sortList();
void search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList());
void filterContent(const QString &query, const QUrl &path);
void setStatus(const PathStatus &status);
FMH::MODEL_LIST list = {{}};
QUrl path;
QString pathName = QString();
QStringList filters = {};
bool onlyDirs = false;
bool hidden = false;
bool foldersFirst = false;
int cloudDepth = 1;
PathStatus m_status;
FMList::SORTBY sort = FMList::SORTBY::MODIFIED;
FMList::FILTER filterType = FMList::FILTER::NONE;
FMList::PATHTYPE pathType = FMList::PATHTYPE::PLACES_PATH;
NavHistory m_navHistory;
public slots:
/**
* @brief refresh
* Refresh the model for new changes
*/
void refresh();
/**
* @brief createDir
* Create a new directory within the current directory
* @param name
* Name of the directory
*/
void createDir(const QString &name);
/**
* @brief copyInto
* Copy a list of file URls into the current directory
* @param urls
* List of files
*/
void copyInto(const QStringList &urls);
/**
* @brief cutInto
* Cut/move a list of file URLs to the current directory
* @param urls
* List of files
*/
void cutInto(const QStringList &urls);
/**
* @brief setDirIcon
* Changes the icon of a directory by making use of the directory config file
* @param index
* Index of the directory in the model
* @param iconName
* Name of the new icon
*/
void setDirIcon(const int &index, const QString &iconName);
/**
* @brief remove
* Remove an item from the model, this does not remove the file from the file system
* @param index
*/
void remove(const int &index);
/**
* @brief search
* Perform a search on the current directory. The search is perfrom in another model than the current one
* @param query
* Query for the search
* @param currentFMList
* The information of the model where the search is going to be performed
*/
void search(const QString &query, const FMList *currentFMList);
/**
* @brief previousPath
* Inmediate previous path
* @return
*/
const QUrl previousPath();
/**
* @brief posteriorPath
* Inmediate posterior path
* @return
*/
const QUrl posteriorPath();
signals:
void pathChanged();
void pathNameChanged();
void pathTypeChanged();
void filtersChanged();
void filterTypeChanged();
void hiddenChanged();
void onlyDirsChanged();
void sortByChanged();
void foldersFirstChanged();
void statusChanged();
void cloudDepthChanged();
void warning(QString message);
void progress(int percent);
void searchResultReady();
};
#endif // FMLIST_H

View file

@ -1,312 +0,0 @@
#include "fmstatic.h"
#include <QDesktopServices>
#include <KRun>
#include <KCoreDirLister>
#include <KFileItem>
#include <KFilePlacesModel>
#include <KIO/CopyJob>
#include <KIO/DeleteJob>
#include <KIO/EmptyTrashJob>
#include <KIO/MkdirJob>
#include <KIO/SimpleJob>
#include <QIcon>
FMStatic::FMStatic(QObject *parent)
: QObject(parent)
{
}
FMH::MODEL_LIST FMStatic::packItems(const QStringList &items, const QString &type)
{
FMH::MODEL_LIST data;
for (const auto &path : items) {
if (QUrl(path).isLocalFile() && !FMH::fileExists(path))
continue;
auto model = FMH::getFileInfoModel(path);
model.insert(FMH::MODEL_KEY::TYPE, type);
data << model;
}
return data;
}
FMH::MODEL_LIST FMStatic::getDefaultPaths()
{
return FMStatic::packItems(FMH::defaultPaths, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]);
}
FMH::MODEL_LIST FMStatic::search(const QString &query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters)
{
FMH::MODEL_LIST content;
if (!path.isLocalFile()) {
qWarning() << "URL recived is not a local file. FM::search" << path;
return content;
}
if (FMStatic::isDir(path)) {
QDir::Filters dirFilter;
dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot);
if (hidden)
dirFilter = dirFilter | QDir::Hidden | QDir::System;
QDirIterator it(path.toLocalFile(), filters, dirFilter, QDirIterator::Subdirectories);
while (it.hasNext()) {
auto url = it.next();
if (it.fileName().contains(query, Qt::CaseInsensitive)) {
content << FMH::getFileInfoModel(QUrl::fromLocalFile(url));
}
}
} else
qWarning() << "Search path does not exists" << path;
qDebug() << content;
return content;
}
FMH::MODEL_LIST FMStatic::getDevices()
{
FMH::MODEL_LIST drives;
return drives;
}
QVariantMap FMStatic::getDirInfo(const QUrl &path)
{
return FMH::getDirInfo(path);
}
QVariantMap FMStatic::getFileInfo(const QUrl &path)
{
return FMH::getFileInfo(path);
}
bool FMStatic::isDefaultPath(const QString &path)
{
return FMH::defaultPaths.contains(path);
}
QUrl FMStatic::parentDir(const QUrl &path)
{
return FMH::parentDir(path);
}
bool FMStatic::isDir(const QUrl &path)
{
if (!path.isLocalFile()) {
// qWarning() << "URL recived is not a local file. FM::isDir" << path;
return false;
}
const QFileInfo file(path.toLocalFile());
return file.isDir();
}
bool FMStatic::isCloud(const QUrl &path)
{
return path.scheme() == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH];
}
bool FMStatic::fileExists(const QUrl &path)
{
return FMH::fileExists(path);
}
QString FMStatic::fileDir(const QUrl &path) // the directory path of the file
{
return FMH::fileDir(path);
}
QString FMStatic::formatSize(const int &size)
{
const QLocale locale;
return locale.formattedDataSize(size);
}
QString FMStatic::formatDate(const QString &dateStr, const QString &format, const QString &initFormat)
{
if (initFormat.isEmpty())
return QDateTime::fromString(dateStr, Qt::TextDate).toString(format);
else
return QDateTime::fromString(dateStr, initFormat).toString(format);
}
QString FMStatic::systemFormatDate(const QString &dateStr)
{
return QLocale::system().toString(QDateTime::fromString(dateStr, Qt::TextDate),
QLocale::ShortFormat);
}
QString FMStatic::formatTime(const qint64 &value)
{
QString tStr;
if (value) {
QTime time((value / 3600) % 60, (value / 60) % 60, value % 60, (value * 1000) % 1000);
QString format = "mm:ss";
if (value > 3600)
format = "hh:mm:ss";
tStr = time.toString(format);
}
return tStr.isEmpty() ? "00:00" : tStr;
}
QString FMStatic::homePath()
{
return FMH::HomePath;
}
bool FMStatic::copy(const QList<QUrl> &urls, const QUrl &destinationDir)
{
auto job = KIO::copy(urls, destinationDir);
job->start();
return true;
}
bool FMStatic::cut(const QList<QUrl> &urls, const QUrl &where)
{
return FMStatic::cut(urls, where, QString());
}
bool FMStatic::cut(const QList<QUrl> &urls, const QUrl &where, const QString &name)
{
QUrl _where = where;
if (!name.isEmpty())
_where = QUrl(where.toString() + "/" + name);
auto job = KIO::move(urls, _where, KIO::HideProgressInfo);
job->start();
return true;
}
bool FMStatic::removeFiles(const QList<QUrl> &urls)
{
auto job = KIO::del(urls);
job->start();
return true;
}
void FMStatic::moveToTrash(const QList<QUrl> &urls)
{
auto job = KIO::trash(urls);
job->start();
}
void FMStatic::emptyTrash()
{
auto job = KIO::emptyTrash();
job->start();
}
bool FMStatic::removeDir(const QUrl &path)
{
bool result = true;
QDir dir(path.toLocalFile());
qDebug() << "TRYING TO REMOVE DIR" << path << path.toLocalFile();
if (dir.exists()) {
Q_FOREACH (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) {
result = removeDir(QUrl::fromLocalFile(info.absoluteFilePath()));
} else {
result = QFile::remove(info.absoluteFilePath());
}
if (!result) {
return result;
}
}
result = dir.rmdir(path.toLocalFile());
}
return result;
}
bool FMStatic::rename(const QUrl &url, const QString &name)
{
return FMStatic::cut({url}, QUrl(url.toString().left(url.toString().lastIndexOf("/"))), name);
}
bool FMStatic::createDir(const QUrl &path, const QString &name)
{
auto job = KIO::mkdir(name.isEmpty() ? path : QUrl(path.toString() + "/" + name));
job->start();
return true;
}
bool FMStatic::createFile(const QUrl &path, const QString &name)
{
QFile file(path.toLocalFile() + "/" + name);
if (file.open(QIODevice::ReadWrite)) {
file.close();
return true;
}
return false;
}
bool FMStatic::createSymlink(const QUrl &path, const QUrl &where)
{
qDebug() << "trying to create symlink" << path << where;
const auto job = KIO::link({path}, where);
job->start();
return true;
}
bool FMStatic::openUrl(const QUrl &url)
{
KRun::runUrl(url, FMH::getFileInfoModel(url)[FMH::MODEL_KEY::MIME], nullptr, false, KRun::RunFlag::DeleteTemporaryFiles);
return true;
}
void FMStatic::openLocation(const QStringList &urls)
{
for (const auto &url : qAsConst(urls))
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(url).dir().absolutePath()));
}
const QVariantMap FMStatic::dirConf(const QUrl &path)
{
return FMH::dirConf(path);
}
void FMStatic::setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value)
{
FMH::setDirConf(path, group, key, value);
}
bool FMStatic::checkFileType(const int &type, const QString &mimeTypeName)
{
return FMH::checkFileType(static_cast<FMH::FILTER_TYPE>(type), mimeTypeName);
}
static bool doNameFilter(const QString &name, const QStringList &filters)
{
const auto filtersAccumulate = std::accumulate(filters.constBegin(), filters.constEnd(), QVector<QRegExp> {}, [](QVector<QRegExp> &res, const QString &filter) -> QVector<QRegExp> {
res.append(QRegExp(filter, Qt::CaseInsensitive, QRegExp::Wildcard));
return res;
});
for (const auto &filter : filtersAccumulate) {
if (filter.exactMatch(name)) {
return true;
}
}
return false;
}
QStringList FMStatic::nameFilters(const int &type)
{
return FMH::FILTER_LIST[static_cast<FMH::FILTER_TYPE>(type)];
}
QString FMStatic::iconName(const QString &value)
{
return FMH::getIconName(value);
}

View file

@ -1,353 +0,0 @@
#ifndef FMSTATIC_H
#define FMSTATIC_H
#include "fmh.h"
#include <QObject>
/**
* @brief The FMStatic class
* STatic file management methods, this class has a constructor only to register to QML, however all methods are static.
*/
class FMStatic : public QObject
{
Q_OBJECT
public:
explicit FMStatic(QObject *parent = nullptr);
public slots:
/**
* @brief search
* Search for files in a path using filters
* @param query
* Term to be searched, such as ".qml" or "music"
* @param path
* The path to perform the search upon
* @param hidden
* If should also search for hidden files
* @param onlyDirs
* If only searching for directories and not files
* @param filters
* List of filter patterns such as {"*.qml"}, it can use regular expressions
* @return
* The search results are returned as a FMH::MODEL_LIST
*/
static FMH::MODEL_LIST search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList());
/**
* @brief getDevices
* Devices mounted to the file system
* @return
* Represented as a FMH::MODEL_LIST
*/
static FMH::MODEL_LIST getDevices();
/**
* @brief getDefaultPaths
* A model list of the default paths in most systems, such as Home, Pictures, Video, Downloads, Music and Documents folders
* @return
*/
static FMH::MODEL_LIST getDefaultPaths();
/**
* @brief packItems
* Given a list of path URLs pack all the info of such files as a FMH::MODEL_LIST
* @param items
* List of local URLs
* @param type
* The type of the list of urls, such as local, remote etc. This value is inserted with the key FMH::MODEL_KEY::TYPE
* @return
*/
static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type);
/**
* @brief copy
* Perfom a copy of the files to the passed destination
* @param urls
* List of URLs to be copy
* @param destinationDir
* Destination
* @return
* Return if the operation has been succesfull
*/
static bool copy(const QList<QUrl> &urls, const QUrl &destinationDir);
/**
* @brief cut
* Perform a move/cut of a list of files to a destination. This function also moves the associated tags if the tags component has been enabled COMPONENT_TAGGING
* @param urls
* List of URLs to be moved
* @param where
* Destination path
* @return
* If the operation has been sucessfull
*/
static bool cut(const QList<QUrl> &urls, const QUrl &where);
/**
* @brief cut
* @param urls
* @param where
* @param name
* New name of the files to be moved
* @return
*/
static bool cut(const QList<QUrl> &urls, const QUrl &where, const QString &name);
/**
* @brief removeFiles
* List of files to be removed completely. This function also removes the assciated tags to the files if the tagging component has been enabled COMPONENT_TAGGING
* @param urls
* @return
* If the operation has been sucessfull
*/
static bool removeFiles(const QList<QUrl> &urls);
/**
* @brief removeDir
* Remove a directory recursively
* @param path
* Path URL to be rmeoved
* @return
* If the operation has been sucessfull
*/
static bool removeDir(const QUrl &path);
/**
* @brief formatSize
* Format a file size
* @param size
* size in bytes
* @return
* Formated into a readable string
*/
static QString formatSize(const int &size);
/**
* @brief formatTime
* Format a milliseconds value to a readable format
* @param value
* Milliseconds
* @return
* Readable formated value
*/
static QString formatTime(const qint64 &value);
/**
* @brief formatDate
* Given a date string, a format and a intended format return a readable string
* @param dateStr
* Date format
* @param format
* Intended format, by default "dd/MM/yyyy"
* @param initFormat
* Date format
* @return
*/
static QString formatDate(const QString &dateStr, const QString &format = QString("dd/MM/yyyy"), const QString &initFormat = QString());
static QString systemFormatDate(const QString &dateStr);
/**
* @brief homePath
* The default home path in different systems
* @return
*/
static QString homePath();
/**
* @brief parentDir
* Given a file url return its parent directory
* @param path
* The file URL
* @return
* The parent directory URL if it exists otherwise returns the passed URL
*/
static QUrl parentDir(const QUrl &path);
/**
* @brief getDirInfo
* Get info of a directory packed as a QVariantMap model
* @param path
* Path URL
* @return
*/
static QVariantMap getDirInfo(const QUrl &path);
/**
* @brief getFileInfo
* Get file info
* @param path
* @return
* File info packed as a QVariantMap model
*/
static QVariantMap getFileInfo(const QUrl &path);
/**
* @brief isDefaultPath
* Checks if a given path URL is a default path as in returned by the defaultPaths method
* @param path
* @return
*/
static bool isDefaultPath(const QString &path);
/**
* @brief isDir
* If a local file URL is a directory
* @param path
* File URL
* @return
*/
static bool isDir(const QUrl &path);
/**
* @brief isCloud
* If a path is a URL server instead of a local file
* @param path
* @return
*/
static bool isCloud(const QUrl &path);
/**
* @brief fileExists
* Checks if a local file exists in the file system
* @param path
* File URL
* @return
* Existance
*/
static bool fileExists(const QUrl &path);
/**
* if the url is a file path then it returns its directory
* and if it is a directory returns the same path
* */
/**
* @brief fileDir
* Gives the directory URL path of a file, and if it is a directory returns the same path
* @param path
* File path URL
* @return
* The directory URL
*/
static QString fileDir(const QUrl &path);
/**
* @brief dirConf
* The config values of a directory, such values can be any from iconname to specific ones. The config file is stored in the directory as .dir
* @param path
* @return
*/
static const QVariantMap dirConf(const QUrl &path);
/**
* @brief setDirConf
* Write a config key-value to the directory config file
* @param path
* @param group
* @param key
* @param value
*/
static void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value);
/**
* @brief checkFileType
* Checks if a mimetype belongs to a file type, for example image/jpg belong to the type FMH::FILTER_TYPE
* @param type
* FMH::FILTER_TYPE value
* @param mimeTypeName
* @return
*/
static bool checkFileType(const int &type, const QString &mimeTypeName);
/**
* @brief moveToTrash
* Moves to the trash can the file URLs. The associated tags are kept in case the files are restored.
* @param urls
*/
static void moveToTrash(const QList<QUrl> &urls);
/**
* @brief emptyTrash
* Empty the trash casn
*/
static void emptyTrash();
/**
* @brief rename
* Rename a file to a new name
* @param url
* File URL to be renamed
* @param name
* The short new name of the file, not the new URL, for setting a new URl use cut instead.
* @return
*/
static bool rename(const QUrl &url, const QString &name);
/**
* @brief createDir
* Creates a directory given a base path and a directory name
* @param path
* Base directory path
* @param name
* New directory name
* @return
* If the operation was sucessfull
*/
static bool createDir(const QUrl &path, const QString &name);
/**
* @brief createFile
* Creates a file given the base directory path and a short file name
* @param path
* Base directory path
* @param name
* Name of the new file to be created with the extension
* @return
*/
static bool createFile(const QUrl &path, const QString &name);
/**
* @brief createSymlink
* Creates a symlink
* @param path
* File to be symlinked
* @param where
* Destination of the symlink
* @return
*/
static bool createSymlink(const QUrl &path, const QUrl &where);
/**
* @brief openUrl
* Given a URL it tries to open it using the default app associated to it
* @param url
* The URL to be open
* @return
*/
static bool openUrl(const QUrl &url);
/**
* @brief openLocation
* Open with the default file manager a list of URLs
* @param urls
*/
static void openLocation(const QStringList &urls);
/**
* @brief nameFilters
* Given a filter type return a list of associated name filters, as in suffixes.
* @param type
* The filter type to be mapped to a FMH::FILTER_TYPE
*/
static QStringList nameFilters(const int &type);
/**
* @brief iconName
* Get the icon name associated to the file or name.
* @param value
* The file path or file name
*/
static QString iconName(const QString &value);
};
#endif // FMSTATIC_H

View file

@ -1,113 +0,0 @@
/*
* Copyright 2018 Camilo Higuita <milo.h@aol.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "handy.h"
#include "fmh.h"
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QIcon>
#include <QMimeData>
#include <QOperatingSystemVersion>
#include <QDBusInterface>
Handy::Handy(QObject *parent)
: QObject(parent)
{
}
QVariantMap Handy::userInfo()
{
QString name = qgetenv("USER");
if (name.isEmpty())
name = qgetenv("USERNAME");
return QVariantMap({{FMH::MODEL_NAME[FMH::MODEL_KEY::NAME], name}});
}
QString Handy::getClipboardText()
{
auto clipbopard = QApplication::clipboard();
auto mime = clipbopard->mimeData();
if (mime->hasText())
return clipbopard->text();
return QString();
}
QVariantMap Handy::getClipboard()
{
QVariantMap res;
auto clipboard = QApplication::clipboard();
auto mime = clipboard->mimeData();
if (mime->hasUrls())
res.insert("urls", QUrl::toStringList(mime->urls()));
if (mime->hasText())
res.insert("text", mime->text());
const QByteArray a = mime->data(QStringLiteral("application/x-kde-cutselection"));
res.insert("cut", (!a.isEmpty() && a.at(0) == '1'));
return res;
}
bool Handy::copyToClipboard(const QVariantMap &value, const bool &cut)
{
auto clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
if (value.contains("urls"))
mimeData->setUrls(QUrl::fromStringList(value["urls"].toStringList()));
if (value.contains("text"))
mimeData->setText(value["text"].toString());
mimeData->setData(QStringLiteral("application/x-kde-cutselection"), cut ? "1" : "0");
clipboard->setMimeData(mimeData);
return true;
}
void Handy::setAsWallpaper(const QUrl &url)
{
if (!url.isLocalFile())
return;
QDBusInterface iface("org.cutefish.Settings", "/Theme",
"org.cutefish.Theme",
QDBusConnection::sessionBus(), nullptr);
if (iface.isValid())
iface.call("setWallpaper", url.toLocalFile());
}
bool Handy::copyTextToClipboard(const QString &text)
{
QApplication::clipboard()->setText(text);
return true;
}
int Handy::version()
{
return QOperatingSystemVersion::current().majorVersion();
}

View file

@ -1,81 +0,0 @@
/*
* Copyright 2018 Camilo Higuita <milo.h@aol.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef HANDY_H
#define HANDY_H
#include <QObject>
#include <QVariantMap>
/*!
* \brief The Handy class
* Contains useful static methods to be used as an attached property to the Maui application
*/
class Handy : public QObject
{
Q_OBJECT
public:
Handy(QObject *parent = nullptr);
public slots:
/*!
* \brief Returns the major version of the current OS
*
* This function is static.
* \return Major OS version
*/
static int version();
/*!
* \brief Returns a QVariantMap containing basic information about the current user
*
* The pairs keys for the information returned are:
* "name"
* \return QVariantMap with user info
*/
static QVariantMap userInfo();
/*!
* \brief Returns the text contained in the clipboard
* \return QString containing clipboard text
*/
static QString getClipboardText();
static QVariantMap getClipboard();
/*!
* \brief Copies text to the clipboard
* \param text text to be copied to the clipboard
* \return
*/
static bool copyTextToClipboard(const QString &text);
/**
* @brief copyToClipboard
* @param value
* @param cut
* @return
*/
static bool copyToClipboard(const QVariantMap &value, const bool &cut = false);
static void setAsWallpaper(const QUrl &url);
};
#endif // HANDY_H

View file

@ -1,33 +0,0 @@
#include "iconthemeprovider.h"
#include <QIcon>
IconThemeProvider::IconThemeProvider()
: QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
QPixmap IconThemeProvider::requestPixmap(const QString &id, QSize *realSize,
const QSize &requestedSize)
{
// Sanitize requested size
QSize size(requestedSize);
if (size.width() < 1)
size.setWidth(1);
if (size.height() < 1)
size.setHeight(1);
// Return real size
if (realSize)
*realSize = size;
// Is it a path?
if (id.startsWith(QLatin1Char('/')))
return QPixmap(id).scaled(size);
// Return icon from theme or fallback to a generic icon
QIcon icon = QIcon::fromTheme(id);
if (icon.isNull())
icon = QIcon::fromTheme(QLatin1String("application-x-desktop"));
return icon.pixmap(size);
}

View file

@ -1,14 +0,0 @@
#ifndef ICONTHEMEPROVIDER_H
#define ICONTHEMEPROVIDER_H
#include <QtQuick/QQuickImageProvider>
class IconThemeProvider : public QQuickImageProvider
{
public:
IconThemeProvider();
QPixmap requestPixmap(const QString &id, QSize *realSize, const QSize &requestedSize);
};
#endif // ICONTHEMEPROVIDER_H

View file

@ -1,20 +0,0 @@
#include "fileitemactions.h"
#include <KMimeTypeTrader>
FileItemActions::FileItemActions(QObject *parent)
: QObject(parent)
{
}
KService::List FileItemActions::associatedApplications(const QStringList &mimeTypeList, const QString &traderConstraint)
{
const KService::List firstOffers = KMimeTypeTrader::self()->query(mimeTypeList.first(), "Application", traderConstraint);
QStringList serviceList;
for (int i = 0; i < firstOffers.count(); ++i) {
}
return KService::List();
}

View file

@ -1,18 +0,0 @@
#ifndef FILEITEMACTIONS_H
#define FILEITEMACTIONS_H
#include <QObject>
#include <KService>
class FileItemActions : public QObject
{
Q_OBJECT
public:
explicit FileItemActions(QObject *parent = nullptr);
static KService::List associatedApplications(const QStringList& mimeTypeList, const QString& traderConstraint);
};
#endif // FILEITEMACTIONS_H

File diff suppressed because it is too large Load diff

View file

@ -1,372 +0,0 @@
/***************************************************************************
* Copyright (C) 2008 Fredrik Höglund <fredrik@kde.org> *
* Copyright (C) 2011 Marco Martin <mart@kde.org> *
* Copyright (C) 2014 by Eike Hein <hein@kde.org> *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef FOLDERMODEL_H
#define FOLDERMODEL_H
#include <QImage>
#include <QItemSelection>
#include <QPointer>
#include <QQmlParserStatus>
#include <QRegExp>
#include <QSet>
#include <QSortFilterProxyModel>
#include <QStringList>
#include <KAbstractViewAdapter>
#include <KActionCollection>
#include <KDirLister>
#include <KFilePreviewGenerator>
#include <KNewFileMenu>
class QDrag;
class QItemSelectionModel;
class QQuickItem;
class KFileCopyToMenu;
class KActionCollection;
class KDirModel;
class KDirWatch;
class KFileItem;
class KFileItemActions;
class KJob;
class KNewFileMenu;
namespace KIO
{
class DropJob;
class StatJob;
}
class ScreenMapper;
class DirLister : public KDirLister
{
Q_OBJECT
public:
explicit DirLister(QObject *parent = nullptr);
~DirLister() override;
Q_SIGNALS:
void error(const QString &string);
protected:
void handleError(KIO::Job *job) override;
};
class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged)
Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged)
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
Q_PROPERTY(bool usedByContainment READ usedByContainment WRITE setUsedByContainment NOTIFY usedByContainmentChanged)
Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged)
Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
Q_PROPERTY(bool sortDesc READ sortDesc WRITE setSortDesc NOTIFY sortDescChanged)
Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
Q_PROPERTY(bool parseDesktopFiles READ parseDesktopFiles WRITE setParseDesktopFiles NOTIFY parseDesktopFilesChanged)
Q_PROPERTY(QObject *viewAdapter READ viewAdapter WRITE setViewAdapter NOTIFY viewAdapterChanged)
Q_PROPERTY(bool previews READ previews WRITE setPreviews NOTIFY previewsChanged)
Q_PROPERTY(QStringList previewPlugins READ previewPlugins WRITE setPreviewPlugins NOTIFY previewPluginsChanged)
Q_PROPERTY(int filterMode READ filterMode WRITE setFilterMode NOTIFY filterModeChanged)
Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged)
Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged)
Q_PROPERTY(QObject *newMenu READ newMenu CONSTANT)
Q_PROPERTY(bool desktopView READ desktopView WRITE setDesktopView NOTIFY desktopViewChanged)
public:
enum DataRole {
BlankRole = Qt::UserRole + 1,
OverlaysRole,
SelectedRole,
IsDirRole,
IsLinkRole,
IsHiddenRole,
UrlRole,
LinkDestinationUrl,
SizeRole,
TypeRole,
FileNameRole,
};
enum FilterMode {
NoFilter = 0,
FilterShowMatches,
FilterHideMatches,
};
enum Status {
None,
Ready,
Listing,
Canceled,
};
Q_ENUM(Status)
explicit FolderModel(QObject *parent = nullptr);
~FolderModel() override;
QHash<int, QByteArray> roleNames() const override;
static QHash<int, QByteArray> staticRoleNames();
void classBegin() override;
void componentComplete() override;
QString url() const;
void setUrl(const QString &url);
QString iconName() const;
QUrl resolvedUrl() const;
Q_INVOKABLE QUrl resolve(const QString &url);
Status status() const;
QString errorString() const;
bool dragging() const;
bool usedByContainment() const;
void setUsedByContainment(bool used);
bool locked() const;
void setLocked(bool locked);
int sortMode() const;
void setSortMode(int mode);
bool sortDesc() const;
void setSortDesc(bool desc);
bool sortDirsFirst() const;
void setSortDirsFirst(bool enable);
bool parseDesktopFiles() const;
void setParseDesktopFiles(bool enable);
QObject *viewAdapter() const;
void setViewAdapter(QObject *adapter);
bool previews() const;
void setPreviews(bool previews);
QStringList previewPlugins() const;
void setPreviewPlugins(const QStringList &previewPlugins);
int filterMode() const;
void setFilterMode(int filterMode);
QString filterPattern() const;
void setFilterPattern(const QString &pattern);
QStringList filterMimeTypes() const;
void setFilterMimeTypes(const QStringList &mimeList);
KFileItem rootItem() const;
Q_INVOKABLE void up();
Q_INVOKABLE void cd(int row);
Q_INVOKABLE void run(int row);
Q_INVOKABLE void runSelected();
Q_INVOKABLE void rename(int row, const QString &name);
Q_INVOKABLE int fileExtensionBoundary(int row);
Q_INVOKABLE bool hasSelection() const;
Q_INVOKABLE bool isSelected(int row);
Q_INVOKABLE void setSelected(int row);
Q_INVOKABLE void selectAll();
Q_INVOKABLE void toggleSelected(int row);
Q_INVOKABLE void setRangeSelected(int anchor, int to);
Q_INVOKABLE void updateSelection(const QVariantList &rows, bool toggle);
Q_INVOKABLE void clearSelection();
Q_INVOKABLE void pinSelection();
Q_INVOKABLE void unpinSelection();
Q_INVOKABLE void addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image);
Q_INVOKABLE void clearDragImages();
Q_INVOKABLE void setDragHotSpotScrollOffset(int x, int y); // FIXME TODO: Propify.
Q_INVOKABLE QPoint dragCursorOffset(int row);
Q_INVOKABLE void dragSelected(int x, int y);
Q_INVOKABLE void drop(QQuickItem *target, QObject *dropEvent, int row, bool showMenuManually = false);
Q_INVOKABLE void dropCwd(QObject *dropEvent);
Q_INVOKABLE bool isBlank(int row) const;
Q_INVOKABLE QAction *action(const QString &name) const;
QObject *newMenu() const;
Q_INVOKABLE void updateActions();
Q_INVOKABLE void openContextMenu(QQuickItem *visualParent = nullptr, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
Q_INVOKABLE void linkHere(const QUrl &sourceUrl);
Q_INVOKABLE void openPropertiesDialog();
Q_INVOKABLE QString desktopPath() const;
Q_INVOKABLE QString homePath() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int indexForUrl(const QUrl &url) const;
KFileItem itemForIndex(const QModelIndex &index) const;
bool isDir(const QModelIndex &index, const KDirModel *dirModel) const;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
Qt::DropActions supportedDragActions() const override;
Qt::DropActions supportedDropActions() const override;
Q_INVOKABLE void paste();
Q_INVOKABLE void copy();
Q_INVOKABLE void cut();
Q_INVOKABLE void deleteSelected();
Q_INVOKABLE void openSelected();
Q_INVOKABLE void undo();
Q_INVOKABLE void refresh();
Q_INVOKABLE void createFolder();
Q_INVOKABLE void setAsWallpaper();
Q_INVOKABLE void openSettings(const QString &itemName);
bool desktopView() const;
void setDesktopView(bool value);
void setScreen(int screen);
bool eventFilter(QObject *watched, QEvent *event) override;
Q_SIGNALS:
void urlChanged() const;
void listingCompleted() const;
void listingCanceled() const;
void iconNameChanged() const;
void resolvedUrlChanged() const;
void statusChanged() const;
void errorStringChanged() const;
void draggingChanged() const;
void usedByContainmentChanged() const;
void lockedChanged() const;
void sortModeChanged() const;
void sortDescChanged() const;
void sortDirsFirstChanged() const;
void parseDesktopFilesChanged() const;
void viewAdapterChanged();
void previewsChanged() const;
void previewPluginsChanged() const;
void filterModeChanged() const;
void filterPatternChanged() const;
void filterMimeTypesChanged() const;
void screenChanged() const;
void requestRename() const;
void move(int x, int y, QList<QUrl> urls);
void popupMenuAboutToShow(KIO::DropJob *dropJob, QMimeData *mimeData, int x, int y);
void desktopViewChanged();
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool matchMimeType(const KFileItem &item) const;
bool matchPattern(const KFileItem &item) const;
private Q_SLOTS:
void dragSelectedInternal(int x, int y);
void dirListFailed(const QString &error);
void statResult(KJob *job);
void evictFromIsDirCache(const KFileItemList &items);
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void pasteTo();
void moveSelectedToTrash();
void emptyTrashBin();
void restoreSelectedFromTrash();
void undoTextChanged(const QString &text);
void invalidateIfComplete();
void invalidateFilterIfComplete();
void newFileMenuItemCreated(const QUrl &url);
private:
struct DragImage {
int row;
QRect rect;
QPoint cursorOffset;
QImage image;
bool blank;
};
void createActions();
void addDragImage(QDrag *drag, int x, int y);
void setStatus(Status status);
static bool isTrashEmpty();
QList<QUrl> selectedUrls() const;
KDirModel *m_dirModel;
KDirWatch *m_dirWatch;
QString m_url;
mutable QHash<QUrl, bool> m_isDirCache;
mutable QHash<QUrl, KIO::StatJob *> m_isDirJobs;
QItemSelectionModel *m_selectionModel;
QItemSelection m_pinnedSelection;
QModelIndexList m_dragIndexes;
QHash<int, DragImage *> m_dragImages;
QPoint m_dragHotSpotScrollOffset;
bool m_dragInProgress;
bool m_urlChangedWhileDragging;
// target filename to target position of a drop event, note that this deliberately
// is not using the URL to easily support desktop:/ URL schemes
QHash<QString, QPoint> m_dropTargetPositions;
QTimer *m_dropTargetPositionsCleanup;
QPointer<KFilePreviewGenerator> m_previewGenerator;
QPointer<KAbstractViewAdapter> m_viewAdapter;
KActionCollection m_actionCollection;
KNewFileMenu *m_newMenu;
KFileItemActions *m_fileItemActions;
KFileCopyToMenu *m_copyToMenu;
Status m_status = Status::None;
QString m_errorString;
bool m_usedByContainment;
bool m_locked;
int m_sortMode; // FIXME TODO: Enumify.
bool m_sortDesc;
bool m_sortDirsFirst;
bool m_parseDesktopFiles;
bool m_previews;
// An empty previewPlugin list means use default.
// We don't want to leak that fact to the QML side, however, so the property stays empty
// and internally we operate on effectivePreviewPlugins instead.
QStringList m_previewPlugins;
QStringList m_effectivePreviewPlugins;
FilterMode m_filterMode;
QString m_filterPattern;
bool m_filterPatternMatchAll;
QSet<QString> m_mimeSet;
QList<QRegExp> m_regExps;
int m_screen = -1;
bool m_screenUsed;
bool m_complete;
QPoint m_menuPosition;
bool m_isDesktopView;
};
#endif

View file

@ -1,72 +0,0 @@
/***************************************************************************
* Copyright (C) 2014 by Eike Hein <hein@kde.org> *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef ITEMVIEWADAPTER_H
#define ITEMVIEWADAPTER_H
#include <QRect>
#include <KAbstractViewAdapter>
class ItemViewAdapter : public KAbstractViewAdapter
{
Q_OBJECT
Q_PROPERTY(QObject *adapterView READ adapterView WRITE setAdapterView NOTIFY adapterViewChanged)
Q_PROPERTY(QAbstractItemModel *adapterModel READ adapterModel WRITE setAdapterModel NOTIFY adapterModelChanged)
Q_PROPERTY(int adapterIconSize READ adapterIconSize WRITE setAdapterIconSize NOTIFY adapterIconSizeChanged)
Q_PROPERTY(QRect adapterVisibleArea READ adapterVisibleArea WRITE setAdapterVisibleArea NOTIFY adapterVisibleAreaChanged)
public:
explicit ItemViewAdapter(QObject *parent = nullptr);
QAbstractItemModel *model() const override;
QSize iconSize() const override;
QPalette palette() const override;
QRect visibleArea() const override;
QRect visualRect(const QModelIndex &index) const override;
void connect(Signal signal, QObject *receiver, const char *slot) override;
QObject *adapterView() const;
void setAdapterView(QObject *view);
QAbstractItemModel *adapterModel() const;
void setAdapterModel(QAbstractItemModel *model);
int adapterIconSize() const;
void setAdapterIconSize(int size);
QRect adapterVisibleArea() const;
void setAdapterVisibleArea(QRect rect);
Q_SIGNALS:
void viewScrolled() const;
void adapterViewChanged() const;
void adapterModelChanged() const;
void adapterIconSizeChanged() const;
void adapterVisibleAreaChanged() const;
private:
QObject *m_adapterView;
QAbstractItemModel *m_adapterModel;
int m_adapterIconSize;
QRect m_adapterVisibleArea;
};
#endif

View file

@ -1,126 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 "pathlist.h"
PathList::PathList(QObject *parent)
: BaseList(parent)
{
}
QVariantMap PathList::get(const int &index) const
{
if (this->list.isEmpty() || index >= this->list.size() || index < 0) {
return QVariantMap();
}
const auto model = this->list.at(index);
return FMH::toMap(model);
}
QString PathList::getPath() const
{
return this->m_path;
}
const FMH::MODEL_LIST &PathList::items() const
{
return this->list;
}
void PathList::setList()
{
const auto paths = PathList::splitPath(m_path);
if (this->list.isEmpty()) {
emit this->preListChanged();
this->list << paths;
emit this->postListChanged();
} else {
const int index = [&]() -> int {
int i = 0;
for (const auto &item : qAsConst(list)) {
if (i < paths.size()) {
if (item[FMH::MODEL_KEY::PATH] != paths[i][FMH::MODEL_KEY::PATH]) {
break;
} else
i++;
} else
break;
}
return i;
}();
for (auto i = this->list.size() - 1; i >= index; i--) {
emit preItemRemoved(i);
this->list.removeAt(i);
emit postItemRemoved();
}
for (auto i = index; i < paths.size(); i++) {
emit preItemAppended();
this->list << paths[i];
emit postItemAppended();
}
}
}
void PathList::setPath(const QString &path)
{
if (path == this->m_path)
return;
this->m_path = path;
this->setList();
emit this->pathChanged();
qDebug() << this->list;
}
FMH::MODEL_LIST PathList::splitPath(const QString &path)
{
FMH::MODEL_LIST res;
QString _url = path;
while (_url.endsWith("/"))
_url.chop(1);
_url += "/";
const auto count = _url.count("/");
for (auto i = 0; i < count; i++) {
_url = QString(_url).left(_url.lastIndexOf("/"));
auto label = QString(_url).right(_url.length() - _url.lastIndexOf("/") - 1);
if (label.isEmpty())
continue;
if (label.contains(":") && i == count - 1) // handle the protocol
{
res << FMH::MODEL {{FMH::MODEL_KEY::LABEL, "/"}, {FMH::MODEL_KEY::PATH, _url + "///"}};
break;
}
res << FMH::MODEL {{FMH::MODEL_KEY::LABEL, label}, {FMH::MODEL_KEY::PATH, _url}};
}
std::reverse(res.begin(), res.end());
return res;
}

View file

@ -1,71 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 camilo <chiguitar@unal.edu.co>
*
* 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 PATHLIST_H
#define PATHLIST_H
#include "baselist.h"
/**
* @brief The PathList class
*/
class PathList : public BaseList
{
Q_OBJECT
Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
public:
PathList(QObject *parent = nullptr);
const FMH::MODEL_LIST &items() const override;
/**
* @brief setPath
* @param path
*/
void setPath(const QString &path);
/**
* @brief getPath
* @return
*/
QString getPath() const;
/**
* @brief get
* @param index
* @return
*/
QVariantMap get(const int &index) const;
private:
FMH::MODEL_LIST list;
QString m_path;
static FMH::MODEL_LIST splitPath(const QString &path);
void setList();
signals:
/**
* @brief pathChanged
*/
void pathChanged();
};
#endif // PATHLIST_H

View file

@ -1,233 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2018 camilo <email>
*
* 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 "placeslist.h"
#include "fm.h"
#include <QEventLoop>
#include <QFileSystemWatcher>
#include <QIcon>
#include <QTimer>
#include <KFilePlacesModel>
PlacesList::PlacesList(QObject *parent)
: BaseList(parent)
, fm(new FM(this))
, model(new KFilePlacesModel(this))
, watcher(new QFileSystemWatcher(this))
{
/*
* The watcher signal returns a local file URL withouth a scheme, and the model is using a local file URL with file:// scheme.
* So those need to be correctly mapped
* */
connect(watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) {
if (this->count.contains(QUrl::fromLocalFile(path).toString())) {
const auto oldCount = this->count[QUrl::fromLocalFile(path).toString()];
const auto index = this->indexOf(FMH::MODEL_KEY::PATH, QUrl::fromLocalFile(path).toString());
const QDir dir(path);
const auto newCount = dir.count();
int count = newCount - oldCount;
this->list[index][FMH::MODEL_KEY::COUNT] = QString::number(std::max(0, count));
emit this->updateModel(index, {FMH::MODEL_KEY::COUNT});
}
});
connect(this->model, &KFilePlacesModel::reloaded, [this]() {
this->setList();
});
connect(this->model, &KFilePlacesModel::rowsInserted, [this](const QModelIndex, int, int) {
this->setList();
emit this->bookmarksChanged();
/*emit this->preListChanged();
for (int i = first; i <= last; i++)
{
const QModelIndex index = model->index(i, 0);
if(this->groups.contains(model->groupType(index)))
{
this->list << getGroup(*this->model, static_cast<FMH::PATHTYPE_KEY>(model->groupType(index)));
}
}
emit this->postListChanged(); */
}); // TODO improve the usage of the model
}
void PlacesList::watchPath(const QString &path)
{
if (path.isEmpty() || !FMH::fileExists(path) || !QUrl(path).isLocalFile())
return;
this->watcher->addPath(QUrl(path).toLocalFile());
}
void PlacesList::componentComplete()
{
connect(this, &PlacesList::groupsChanged, this, &PlacesList::setList);
this->setList();
}
const FMH::MODEL_LIST &PlacesList::items() const
{
return this->list;
}
FMH::MODEL_LIST PlacesList::getGroup(const KFilePlacesModel &model, const FMH::PATHTYPE_KEY &type)
{
FMH::MODEL_LIST res;
if (type == FMH::PATHTYPE_KEY::QUICK_PATH) {
res << FMH::MODEL {{FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH] + "fav"}, {FMH::MODEL_KEY::ICON, "love"}, {FMH::MODEL_KEY::LABEL, "Favorite"}, {FMH::MODEL_KEY::TYPE, "Quick"}};
#if defined Q_OS_LINUX && !defined Q_OS_ANDROID
res << FMH::MODEL {{FMH::MODEL_KEY::PATH, "recentdocuments:///"}, {FMH::MODEL_KEY::ICON, "view-media-recent"}, {FMH::MODEL_KEY::LABEL, "Recent"}, {FMH::MODEL_KEY::TYPE, "Quick"}};
#endif
return res;
}
if (type == FMH::PATHTYPE_KEY::PLACES_PATH) {
res << FMStatic::getDefaultPaths();
}
const auto group = model.groupIndexes(static_cast<KFilePlacesModel::GroupType>(type));
res << std::accumulate(group.constBegin(), group.constEnd(), FMH::MODEL_LIST(), [&model, &type](FMH::MODEL_LIST &list, const QModelIndex &index) -> FMH::MODEL_LIST {
const QUrl url = model.url(index);
if (type == FMH::PATHTYPE_KEY::PLACES_PATH && FMH::defaultPaths.contains(url.toString()))
return list;
if (type == FMH::PATHTYPE_KEY::PLACES_PATH && url.isLocalFile() && !FMH::fileExists(url))
return list;
list << FMH::MODEL {{FMH::MODEL_KEY::PATH, url.toString()},
{FMH::MODEL_KEY::URL, url.toString()},
{FMH::MODEL_KEY::ICON, model.icon(index).name()},
{FMH::MODEL_KEY::LABEL, model.text(index)},
{FMH::MODEL_KEY::NAME, model.text(index)},
{FMH::MODEL_KEY::TYPE, type == FMH::PATHTYPE_KEY::PLACES_PATH ? FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::BOOKMARKS_PATH] : FMH::PATHTYPE_LABEL[type]}};
return list;
});
return res;
}
void PlacesList::setList()
{
if (this->groups.isEmpty())
return;
emit this->preListChanged();
this->list.clear();
for (const auto &group : qAsConst(this->groups)) {
switch (group) {
case FMH::PATHTYPE_KEY::PLACES_PATH:
this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::PLACES_PATH);
break;
case FMH::PATHTYPE_KEY::QUICK_PATH:
this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::QUICK_PATH);
break;
case FMH::PATHTYPE_KEY::APPS_PATH:
this->list << FM::getAppsPath();
break;
case FMH::PATHTYPE_KEY::DRIVES_PATH:
this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::DRIVES_PATH);
break;
case FMH::PATHTYPE_KEY::REMOTE_PATH:
this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::REMOTE_PATH);
break;
case FMH::PATHTYPE_KEY::REMOVABLE_PATH:
this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::REMOVABLE_PATH);
break;
}
}
this->setCount();
emit this->postListChanged();
}
void PlacesList::setCount()
{
this->watcher->removePaths(this->watcher->directories());
for (auto &data : this->list) {
const auto path = data[FMH::MODEL_KEY::URL];
if (FMStatic::isDir(path)) {
data.insert(FMH::MODEL_KEY::COUNT, "0");
QDir dir(QUrl(path).toLocalFile());
const auto count = dir.count();
this->count.insert(path, count);
this->watchPath(path);
}
}
}
QList<int> PlacesList::getGroups() const
{
return this->groups;
}
void PlacesList::setGroups(const QList<int> &value)
{
if (this->groups == value)
return;
this->groups = value;
emit this->groupsChanged();
}
QVariantMap PlacesList::get(const int &index) const
{
if (index >= this->list.size() || index < 0)
return QVariantMap();
const auto model = this->list.at(index);
return FMH::toMap(model);
}
void PlacesList::clearBadgeCount(const int &index)
{
this->list[index][FMH::MODEL_KEY::COUNT] = "0";
emit this->updateModel(index, {FMH::MODEL_KEY::COUNT});
}
void PlacesList::removePlace(const int &index)
{
if (index >= this->list.size() || index < 0)
return;
emit this->preItemRemoved(index);
this->model->removePlace(this->model->closestItem(this->list.at(index)[FMH::MODEL_KEY::PATH]));
this->list.removeAt(index);
emit this->postItemRemoved();
}
bool PlacesList::contains(const QUrl &path)
{
return this->exists(FMH::MODEL_KEY::PATH, path.toString());
}

View file

@ -1,102 +0,0 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2018 camilo <email>
*
* 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 PLACESLIST_H
#define PLACESLIST_H
#include "baselist.h"
#include <QObject>
class FM;
class KFilePlacesModel;
class QFileSystemWatcher;
class PlacesList : public BaseList
{
Q_OBJECT
Q_PROPERTY(QList<int> groups READ getGroups WRITE setGroups NOTIFY groupsChanged)
public:
PlacesList(QObject *parent = nullptr);
const FMH::MODEL_LIST &items() const override;
QList<int> getGroups() const;
void setGroups(const QList<int> &value);
void componentComplete() override final;
/**
* @brief get
* Gets a item in the model.
* @param index
* Index of the item in the model. The given index is not mapped to a filtered or sorted model
* @return
* The data of the place
*/
QVariantMap get(const int &index) const;
protected:
void setList();
void reset();
public slots:
/**
* @brief clearBadgeCount
* Clears the count associated to a place at a given index in the model
* @param index
*/
void clearBadgeCount(const int &index);
/**
* @brief removePlace
* Removes a place from the model and if the data at the given index is a file URL bookmark then it gets removed from the bookmarks.
* @param index
* Index of the item to be removed in the model
*/
void removePlace(const int &index);
/**
* @brief contains
* Checks of a file URL exists in the places model
* @param path
* File URL to be checked
* @return
* True if it exists otherwise false
*/
bool contains(const QUrl &path);
private:
FM *fm;
FMH::MODEL_LIST list;
KFilePlacesModel *model;
QHash<QString, int> count;
QList<int> groups;
QFileSystemWatcher *watcher;
void watchPath(const QString &path);
void setCount();
static FMH::MODEL_LIST getGroup(const KFilePlacesModel &model, const FMH::PATHTYPE_KEY &type);
signals:
void groupsChanged();
void bookmarksChanged();
};
#endif // PLACESLIST_H

View file

@ -1,33 +0,0 @@
#ifndef RUBBERBAND_H
#define RUBBERBAND_H
#include <QQuickPaintedItem>
class RubberBand : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
explicit RubberBand(QQuickItem *parent = nullptr);
~RubberBand() override;
void paint(QPainter *painter) override;
Q_INVOKABLE bool intersects(const QRectF &rect) const;
QColor color() const;
void setColor(QColor color);
signals:
void colorChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
private:
QRectF m_geometry;
QColor m_color;
};
#endif

View file

@ -1,283 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>BrowserMenu</name>
<message>
<location filename="../qml/BrowserMenu.qml" line="17"/>
<source>New Folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="27"/>
<source>Paste</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="39"/>
<source>Open in Terminal</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="33"/>
<source>Select All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="44"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="53"/>
<source>Empty Trash</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BrowserView</name>
<message>
<location filename="../qml/BrowserView.qml" line="44"/>
<source>No Files</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DesktopView</name>
<message>
<location filename="../src/desktop/desktopview.cpp" line="19"/>
<source>Desktop</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FolderModel</name>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1603"/>
<source>Cut</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1606"/>
<source>Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1609"/>
<source>Undo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1617"/>
<source>Paste</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1624"/>
<source>New Folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1627"/>
<source>New Documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1633"/>
<source>Rename</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1636"/>
<source>Move To Trash</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1639"/>
<source>&amp;Empty Trash</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1642"/>
<source>Restore from trash</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1645"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1648"/>
<source>&amp;Open</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1799"/>
<source>Select All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1816"/>
<source>Change Wallpaper</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1825"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1873"/>
<source>Set as Wallpaper</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1881"/>
<source>&amp;Properties</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ItemMenu</name>
<message>
<location filename="../qml/ItemMenu.qml" line="24"/>
<source>Open</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="32"/>
<source>Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="40"/>
<source>Cut</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="48"/>
<source>Move to Trash</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="58"/>
<source>Rename</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="66"/>
<source>Open in Terminal</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="71"/>
<source>Set As Wallpaper</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="81"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PlacesModel</name>
<message>
<location filename="../src/lib/placesmodel.cpp" line="11"/>
<source>Home</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="18"/>
<source>Desktop</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="25"/>
<source>Documents</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="32"/>
<source>Downloads</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="39"/>
<source>Music</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="46"/>
<source>Pictures</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="53"/>
<source>Videos</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/lib/placesmodel.cpp" line="58"/>
<source>Trash</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PropertiesDialog</name>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="9"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="71"/>
<source>Type:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="80"/>
<source>Location:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="90"/>
<source>Size:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="102"/>
<source>Created:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="114"/>
<source>Modified:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="126"/>
<source>Accessed:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="147"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="152"/>
<source>OK</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="17"/>
<source>File Manager</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View file

@ -1,51 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="zh_CN"> <TS version="2.1" language="zh_CN">
<context>
<name>BrowserMenu</name>
<message>
<location filename="../qml/BrowserMenu.qml" line="17"/>
<source>New Folder</source>
<translation></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="27"/>
<source>Paste</source>
<translation></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="39"/>
<source>Open in Terminal</source>
<translation></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="33"/>
<source>Select All</source>
<translation></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="44"/>
<source>Properties</source>
<translation></translation>
</message>
<message>
<location filename="../qml/BrowserMenu.qml" line="53"/>
<source>Empty Trash</source>
<translation></translation>
</message>
</context>
<context>
<name>BrowserView</name>
<message>
<location filename="../qml/BrowserView.qml" line="44"/>
<source>No Files</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>DesktopView</name> <name>DesktopView</name>
<message> <message>
<location filename="../src/desktop/desktopview.cpp" line="19"/> <location filename="../desktop/desktopview.cpp" line="37"/>
<source>Desktop</source> <source>Desktop</source>
<translation></translation> <translation></translation>
</message> </message>
@ -53,173 +12,138 @@
<context> <context>
<name>FolderModel</name> <name>FolderModel</name>
<message> <message>
<location filename="../src/lib/foldermodel.cpp" line="1603"/> <location filename="../model/foldermodel.cpp" line="407"/>
<source>Cut</source> <source>%1 selected</source>
<translation></translation> <translation> %1 </translation>
</message> </message>
<message> <message>
<location filename="../src/lib/foldermodel.cpp" line="1606"/> <location filename="../model/foldermodel.cpp" line="411"/>
<source>Copy</source> <source>%1 item</source>
<translation></translation> <translation>%1 </translation>
</message> </message>
<message> <message>
<location filename="../src/lib/foldermodel.cpp" line="1609"/> <location filename="../model/foldermodel.cpp" line="415"/>
<source>Undo</source> <source>%1 items</source>
<translation></translation> <translation>%1 </translation>
</message> </message>
<message> <message>
<location filename="../src/lib/foldermodel.cpp" line="1617"/> <location filename="../model/foldermodel.cpp" line="746"/>
<source>Paste</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1624"/>
<source>New Folder</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1627"/>
<source>New Documents</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1633"/>
<source>Rename</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1636"/>
<source>Move To Trash</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1639"/>
<source>&amp;Empty Trash</source>
<translation>&amp;</translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1642"/>
<source>Restore from trash</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1645"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1648"/>
<source>&amp;Open</source>
<translation>&amp;</translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1799"/>
<source>Select All</source> <source>Select All</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/foldermodel.cpp" line="1816"/> <location filename="../model/foldermodel.cpp" line="924"/>
<source>Change Wallpaper</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1825"/>
<source>Properties</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1873"/>
<source>Set as Wallpaper</source>
<translation></translation>
</message>
<message>
<location filename="../src/lib/foldermodel.cpp" line="1881"/>
<source>&amp;Properties</source>
<translation>&amp;</translation>
</message>
</context>
<context>
<name>ItemMenu</name>
<message>
<location filename="../qml/ItemMenu.qml" line="24"/>
<source>Open</source> <source>Open</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="32"/> <location filename="../model/foldermodel.cpp" line="927"/>
<source>Copy</source>
<translation></translation>
</message>
<message>
<location filename="../qml/ItemMenu.qml" line="40"/>
<source>Cut</source> <source>Cut</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="48"/> <location filename="../model/foldermodel.cpp" line="930"/>
<source>Move to Trash</source> <source>Copy</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="58"/> <location filename="../model/foldermodel.cpp" line="933"/>
<source>Paste</source>
<translation></translation>
</message>
<message>
<location filename="../model/foldermodel.cpp" line="936"/>
<source>New Folder</source>
<translation></translation>
</message>
<message>
<location filename="../model/foldermodel.cpp" line="938"/>
<source>Move To Trash</source>
<translation></translation>
</message>
<message>
<location filename="../model/foldermodel.cpp" line="941"/>
<source>Empty Trash</source>
<translation></translation>
</message>
<message>
<location filename="../model/foldermodel.cpp" line="944"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../model/foldermodel.cpp" line="947"/>
<source>Rename</source> <source>Rename</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="66"/> <location filename="../model/foldermodel.cpp" line="950"/>
<source>Open in Terminal</source> <source>Open in Terminal</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="71"/> <location filename="../model/foldermodel.cpp" line="953"/>
<source>Set As Wallpaper</source> <source>Set as Wallpaper</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/ItemMenu.qml" line="81"/> <location filename="../model/foldermodel.cpp" line="956"/>
<source>Properties</source> <source>Properties</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>FolderPage</name>
<message>
<location filename="../qml/FolderPage.qml" line="32"/>
<source>No files</source>
<translation></translation>
</message>
<message>
<location filename="../qml/FolderPage.qml" line="97"/>
<source>Empty Trash</source>
<translation></translation>
</message>
</context>
<context> <context>
<name>PlacesModel</name> <name>PlacesModel</name>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="11"/> <location filename="../model/placesmodel.cpp" line="38"/>
<source>Home</source> <source>Home</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="18"/> <location filename="../model/placesmodel.cpp" line="45"/>
<source>Desktop</source> <source>Desktop</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="25"/> <location filename="../model/placesmodel.cpp" line="52"/>
<source>Documents</source> <source>Documents</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="32"/> <location filename="../model/placesmodel.cpp" line="59"/>
<source>Downloads</source> <source>Downloads</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="39"/> <location filename="../model/placesmodel.cpp" line="66"/>
<source>Music</source> <source>Music</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="46"/> <location filename="../model/placesmodel.cpp" line="73"/>
<source>Pictures</source> <source>Pictures</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="53"/> <location filename="../model/placesmodel.cpp" line="80"/>
<source>Videos</source> <source>Videos</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/lib/placesmodel.cpp" line="58"/> <location filename="../model/placesmodel.cpp" line="85"/>
<source>Trash</source> <source>Trash</source>
<translation></translation> <translation></translation>
</message> </message>
@ -232,50 +156,60 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="71"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="84"/>
<source>Type:</source> <source>Type:</source>
<translation>:</translation> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="80"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="97"/>
<source>Location:</source> <source>Location:</source>
<translation>:</translation> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="90"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="108"/>
<source>Size:</source> <source>Size:</source>
<translation>:</translation> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="102"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="116"/>
<source>Calculating...</source>
<translation>...</translation>
</message>
<message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="121"/>
<source>Created:</source> <source>Created:</source>
<translation>:</translation> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="114"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="134"/>
<source>Modified:</source> <source>Modified:</source>
<translation>:</translation> <translation>:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="126"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="147"/>
<source>Accessed:</source> <source>Accessed:</source>
<translation>访:</translation> <translation>访:</translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="147"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="169"/>
<source>Cancel</source> <source>Cancel</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qml/Dialogs/PropertiesDialog.qml" line="152"/> <location filename="../qml/Dialogs/PropertiesDialog.qml" line="178"/>
<source>OK</source> <source>OK</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../dialogs/propertiesdialog.cpp" line="209"/>
<source>%1 files</source>
<translation>%1 </translation>
</message>
</context> </context>
<context> <context>
<name>main</name> <name>main</name>
<message> <message>
<location filename="../qml/main.qml" line="17"/> <location filename="../qml/main.qml" line="16"/>
<source>File Manager</source> <source>File Manager</source>
<translation></translation> <translation></translation>
</message> </message>

View file

@ -1,22 +1,3 @@
/*
* Copyright © 2008 Fredrik Höglund <fredrik@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "itemviewadapter.h" #include "itemviewadapter.h"
#include <QModelIndex> #include <QModelIndex>
@ -24,7 +5,7 @@
#include <QSize> #include <QSize>
ItemViewAdapter::ItemViewAdapter(QObject *parent) ItemViewAdapter::ItemViewAdapter(QObject *parent)
: KAbstractViewAdapter(parent) : QObject(parent)
, m_adapterView(nullptr) , m_adapterView(nullptr)
, m_adapterModel(nullptr) , m_adapterModel(nullptr)
, m_adapterIconSize(-1) , m_adapterIconSize(-1)
@ -55,7 +36,7 @@ QRect ItemViewAdapter::visualRect(const QModelIndex &index) const
{ {
// FIXME TODO: Implemented on DND branch. // FIXME TODO: Implemented on DND branch.
Q_UNUSED(index) Q_UNUSED(index);
return QRect(); return QRect();
} }

54
widgets/itemviewadapter.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef ITEMVIEWADAPTER_H
#define ITEMVIEWADAPTER_H
#include <QRect>
#include <QAbstractItemModel>
class ItemViewAdapter : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject *adapterView READ adapterView WRITE setAdapterView NOTIFY adapterViewChanged)
Q_PROPERTY(QAbstractItemModel *adapterModel READ adapterModel WRITE setAdapterModel NOTIFY adapterModelChanged)
Q_PROPERTY(int adapterIconSize READ adapterIconSize WRITE setAdapterIconSize NOTIFY adapterIconSizeChanged)
Q_PROPERTY(QRect adapterVisibleArea READ adapterVisibleArea WRITE setAdapterVisibleArea NOTIFY adapterVisibleAreaChanged)
public:
enum Signal { ScrollBarValueChanged, IconSizeChanged };
explicit ItemViewAdapter(QObject *parent = nullptr);
QAbstractItemModel *model() const;
QSize iconSize() const;
QPalette palette() const;
QRect visibleArea() const;
QRect visualRect(const QModelIndex &index) const;
void connect(Signal signal, QObject *receiver, const char *slot);
QObject *adapterView() const;
void setAdapterView(QObject *view);
QAbstractItemModel *adapterModel() const;
void setAdapterModel(QAbstractItemModel *model);
int adapterIconSize() const;
void setAdapterIconSize(int size);
QRect adapterVisibleArea() const;
void setAdapterVisibleArea(QRect rect);
Q_SIGNALS:
void viewScrolled() const;
void adapterViewChanged() const;
void adapterModelChanged() const;
void adapterIconSizeChanged() const;
void adapterVisibleAreaChanged() const;
private:
QObject *m_adapterView;
QAbstractItemModel *m_adapterModel;
int m_adapterIconSize;
QRect m_adapterVisibleArea;
};
#endif

View file

@ -1,3 +1,22 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 "rubberband.h" #include "rubberband.h"
#include <QApplication> #include <QApplication>

52
widgets/rubberband.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: revenmartin <revenmartin@gmail.com>
*
* 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
* 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 RUBBERBAND_H
#define RUBBERBAND_H
#include <QQuickPaintedItem>
class RubberBand : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
explicit RubberBand(QQuickItem *parent = nullptr);
~RubberBand() override;
void paint(QPainter *painter) override;
Q_INVOKABLE bool intersects(const QRectF &rect) const;
QColor color() const;
void setColor(QColor color);
signals:
void colorChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
private:
QRectF m_geometry;
QColor m_color;
};
#endif