Index: denali.pro =================================================================== diff -u -r6c6f1f5d466badd9b4fd67be7c907234c342b2a2 -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- denali.pro (.../denali.pro) (revision 6c6f1f5d466badd9b4fd67be7c907234c342b2a2) +++ denali.pro (.../denali.pro) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -118,8 +118,10 @@ \ # Controllers sources/ApplicationController.h \ sources/device/DeviceController.h \ + sources/model/settings/MSDCardFile.h \ sources/storage/Settings.h \ sources/storage/TreatmentLog.h \ + sources/view/settings/VSDCardFilesModel.h \ sources/wifi/WifiInterface.h \ sources/bluetooth/BluetoothInterface.h \ sources/cloudsync/CloudSyncController.h \ @@ -393,6 +395,7 @@ sources/storage/Settings.cpp \ sources/storage/TreatmentLog.cpp \ sources/view/hd/data/post/VHDPOSTData.cpp \ + sources/view/settings/VSDCardFilesModel.cpp \ sources/wifi/WifiInterface.cpp \ sources/bluetooth/BluetoothInterface.cpp \ sources/cloudsync/CloudSyncController.cpp \ Index: sources/gui/GuiGlobals.cpp =================================================================== diff -u -r159f2bb0317c7c3c0336e4cb80c7fef3f87e329a -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- sources/gui/GuiGlobals.cpp (.../GuiGlobals.cpp) (revision 159f2bb0317c7c3c0336e4cb80c7fef3f87e329a) +++ sources/gui/GuiGlobals.cpp (.../GuiGlobals.cpp) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -49,6 +49,7 @@ #include "VBluetooth.h" #include "VDuetRoWaterDG.h" #include "VCloudSync.h" +#include "VSDCardFilesModel.h" // states data #include "VHDOperationModeData.h" #include "VPreTreatmentStatesData.h" Index: sources/gui/qml/main.qml =================================================================== diff -u -r80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803 -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- sources/gui/qml/main.qml (.../main.qml) (revision 80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803) +++ sources/gui/qml/main.qml (.../main.qml) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -46,6 +46,7 @@ import VBluetooth 0.1 import VDuetRoWaterDG 0.1 import VCloudSync 0.1 +import VSDCardFilesModel 0.1 // States views import VHDOperationMode 0.1 @@ -147,6 +148,7 @@ VBluetooth { id: vBluetooth } VDuetRoWaterDG { id: vDuetRoWaterDG } VCloudSync { id: vCloudSync } + VSDCardFilesModel { id: vSDCardFiles } // ---- States VHDOperationMode { id: vHDOperationMode Index: sources/gui/qml/pages/settings/SettingsExportLogs.qml =================================================================== diff -u -r80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803 -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- sources/gui/qml/pages/settings/SettingsExportLogs.qml (.../SettingsExportLogs.qml) (revision 80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803) +++ sources/gui/qml/pages/settings/SettingsExportLogs.qml (.../SettingsExportLogs.qml) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -307,20 +307,20 @@ // FIXME: there has to be a View for this, and the timer should be removed and an event driven signal should be implemented there. function updateModel() { - _sdcFolderModel.folder = currentTypeFolderApplication // FIXME: there has to be a View for this which also get changed by log type. - _sdcFolderModel.nameFilters = _root.typeFilterAll +// _sdcFolderModel.folder = currentTypeFolderApplication // FIXME: there has to be a View for this which also get changed by log type. +// _sdcFolderModel.nameFilters = _root.typeFilterAll } function clearModel() { - _sdcFolderModel.folder = _root.typePathClr - _sdcFolderModel.nameFilters = _root.typeFilterClr +// _sdcFolderModel.folder = _root.typePathClr +// _sdcFolderModel.nameFilters = _root.typeFilterClr } spacing : 5 width : _contentRect.columnWidthFolder height : parent.height anchors.verticalCenter : parent.verticalCenter Label { id : _sdcLabel - text : _root.sdcLabel + ": %1 files"/*, %2 %3"*/.arg(_sdcFolderView.visibleFileCounter) + (_GuiView.exportCount ? " [Selected: %1]".arg(_GuiView.exportCount ) : "") //.arg("__").arg(_root.dvcUnit) + text : _root.sdcLabel + ": %1 files"/*, %2 %3"*/.arg(_sdcFolderView.count) + (_GuiView.exportCount ? " [Selected: %1]".arg(_GuiView.exportCount ) : "") //.arg("__").arg(_root.dvcUnit) width : parent.width height : _root.headetRowHight verticalAlignment : Text.AlignVCenter @@ -340,27 +340,26 @@ } ListView { id : _sdcFolderView - property int visibleFileCounter : 0 enabled : !_GuiView.exportRunning && ! isUpdatePanels clip : true anchors.fill : parent anchors.margins : 10 anchors.leftMargin : 5 anchors.rightMargin : 5 spacing : 3 - FolderListModel { id : _sdcFolderModel - onStatusChanged: { - // onFolderChanged does not get emitted when switching folders, but status change does. - // Reset the displayed file counter when the state of the model is null - if (_sdcFolderModel.status == FolderListModel.Null) - { - _sdcFolderView.visibleFileCounter = 0 - } - } - showDirs : false - sortField : FolderListModel.Time - folder : _sdcFolderColumn.currentTypeFolderApplication // FIXME: there has to be a View for this which also get changed by log type. - } +// FolderListModel { id : _sdcFolderModel +// onStatusChanged: { +// // onFolderChanged does not get emitted when switching folders, but status change does. +// // Reset the displayed file counter when the state of the model is null +// if (_sdcFolderModel.status == FolderListModel.Null) +// { +// _sdcFolderView.visibleFileCounter = 0 +// } +// } +// showDirs : false +// sortField : FolderListModel.Time +// folder : _sdcFolderColumn.currentTypeFolderApplication // FIXME: there has to be a View for this which also get changed by log type. +// } Component { id : _sdcFileDelegate ProgressBar { id : _sdcItemBackground @@ -375,8 +374,7 @@ : 0 onExportPercentChanged : console.log( "%", exportPercent) - property bool isShownInList : !_GuiView.isPathSymLink(_sdcFolderColumn.currentTypeFolderApplication.replace(typePathPrefix, "") + "/" + fileName) - Component.onCompleted: if ( isShownInList ) _sdcFolderView.visibleFileCounter++ + property bool isShownInList : true//!_GuiView.isPathSymLink(_sdcFolderColumn.currentTypeFolderApplication.replace(typePathPrefix, "") + "/" + fileName) //DEBUG: onInExportListChanged: console.debug(" * ", index, inExportList) function exportListUpdate() { @@ -432,7 +430,7 @@ Text { id : _sdcFileSizeText clip : true width : isShownInList ? _contentRect.columnWidthFileSize : 0 - text : Variables.sizeConverted( fileSize, 1000, 3) + text : Variables.sizeConverted( fileSize_bytes, 1000, 3) color : Colors.textMain font.pixelSize : Fonts.fontPixelTextRectExtra verticalAlignment : Text.AlignVCenter @@ -441,7 +439,7 @@ } } } - model : _sdcFolderModel + model : vSDCardFiles delegate : _sdcFileDelegate } } Index: sources/gui/qml/pages/settings/SettingsStack.qml =================================================================== diff -u -r80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803 -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803) +++ sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -177,6 +177,7 @@ break case SettingsStack.ExportLogs: + vSDCardFiles.doInit() push( _settingsExportLogs ) break Index: sources/model/settings/MSDCardFile.h =================================================================== diff -u --- sources/model/settings/MSDCardFile.h (revision 0) +++ sources/model/settings/MSDCardFile.h (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -0,0 +1,66 @@ +/*! + * + * Copyright (c) 2021-2023 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file MSDCardFile.h + * \author (last) Vy + * \date (last) 18-Jul-2023 + * \author (original) Vy + * \date (original) 18-Jul-2023 + * + */ +#pragma once + +// Qt +#include +#include + +// Project + +// forward declarations +class tst_models; + +namespace Model { + + +/*! + * \brief The SD Card File class + * Provides abstraction for a SD Card File + * \details Holds information about the SD Card File such as filename and size + * + */ +class MSDCardFile { + +public: + struct Data + { + + public: + bool operator==(const Data &d1) { + const QString otherFilePath(QString("%1/%2").arg(d1.filePath()).arg(d1.fileName())); + QFileInfo otherFile(otherFilePath); + + if(_fileInfo.exists() && otherFile.exists()) + return _fileInfo == otherFile; + return false; + } + + explicit Data() {} + explicit Data(const QString &vFilePath) : _fileInfo(QFileInfo(vFilePath)) { } + QString filePath() const { return _fileInfo.path(); } + QString fileName() const { return _fileInfo.fileName (); } + qint64 fileSize_bytes() const { return _fileInfo.size (); } + bool isSymLink() { return _fileInfo.isSymbolicLink(); } + + private: + QFileInfo _fileInfo; + }; + +}; + +} + +typedef Model::MSDCardFile::Data SDCardFileData; Index: sources/view/VView.h =================================================================== diff -u -r159f2bb0317c7c3c0336e4cb80c7fef3f87e329a -ra53bdf104b52cae3a49705a4cc8bd886530084c9 --- sources/view/VView.h (.../VView.h) (revision 159f2bb0317c7c3c0336e4cb80c7fef3f87e329a) +++ sources/view/VView.h (.../VView.h) (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -120,6 +120,7 @@ REGISTER_TYPE( VBluetooth ) \ REGISTER_TYPE( VDuetRoWaterDG ) \ REGISTER_TYPE( VCloudSync ) \ + REGISTER_TYPE( VSDCardFilesModel ) \ /* Alarm */ \ REGISTER_TYPE( VAlarmStatus ) \ REGISTER_TYPE( VAlarmActiveList ) \ Index: sources/view/settings/VSDCardFilesModel.cpp =================================================================== diff -u --- sources/view/settings/VSDCardFilesModel.cpp (revision 0) +++ sources/view/settings/VSDCardFilesModel.cpp (revision a53bdf104b52cae3a49705a4cc8bd886530084c9) @@ -0,0 +1,197 @@ +/*! + * + * Copyright (c) 2021-2023 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file VSDCardFilesModel.cpp + * \author (last) Vy + * \date (last) 16-May-2023 + * \author (original) Behrouz NematiPour + * \date (original) 11-May-2021 + * + */ + +// Qt +#include + +// Project +#include "VSDCardFilesModel.h" +#include "WifiInterface.h" +#include "Logger.h" + +using namespace View; + +VSDCardFilesModel::VSDCardFilesModel(QAbstractListModel *parent) : QAbstractListModel(parent) { +// startTimer(_interval); + initConnections(); + doInit(); +} + +/*! + * \brief VSDCardFilesModel::initConnections + * Makes the necessary connections. Called inside VIEW_DEF_CLASS + */ +void VSDCardFilesModel::initConnections() +{ + // incoming + +} + +/*! + * \brief VSDCardFilesModel::addSDCardFile + * Adds a network to the network model + * \param network (Network) - the network to add to the model + */ +void VSDCardFilesModel::addSDCardFile(const SDCardFileData &vFileData) +{ + qDebug()<< "adding to SD card list : "<< vFileData.filePath() << "/" << vFileData.fileName(); + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + _sdCardFiles << vFileData; + endInsertRows(); +} + +///*! +// * \brief VNetworkModel::removeRows +// * Removes all rows from the model +// */ +//void VSDCardFilesModel::removeAllRows() +//{ +// beginRemoveRows(QModelIndex(), 0, rowCount()); +// _networks.clear(); +// endRemoveRows(); +//} + +/*! + * \brief VSDCardFilesModel::doInit + * \details Initializes the view or what needs to be done when for example getting into the WiFi setting screen (do scan for now). + */ +void VSDCardFilesModel::doInit() +{ + // Do the first population + + // WIP ! + QDir dir("/media/sd-card/log/"); + dir.setFilter(QDir::NoDotAndDotDot | QDir::Files); // not using "| QDir::NoSymLinks" dur to performance + dir.setSorting(QDir::Time); + QStringList listOfFiles = dir.entryList(); + + listOfFiles.append(listOfFiles); + + /******* + * // TODO + * NOTE TO FUTURE VY : TODO -------------------------- + * + * Need a QSortFilterProxyModel that can sort the file list + * + * To get all files in parent and subdir, use QDirIterator with : + * + * QDirIterator it("/etc", QDirIterator::Subdirectories); + * while (it.hasNext()) { .... } + * + * this will give us files from top and subdir, but it does not sort...This is + * where the ProxyModel comes in for sorting. + * + * The result from the QDirIterator will be the "source model". the source model will add/remove + * the added/removed files and the proxymodel will do the automatic sorting/filtering + * + * Need to figure out how to use one model for 3 directories, then use the proxy model to filter based on + * log category this will improve the performance since we are not re-creating the model each time + * + * The exposed model to the QML is the proxyModel. The proxyModel and the abstractlistmodel are both + * derived from the abstractItemModel. + * + * Get this ^^^ to work first and then refactor to re-use in USB - maybe + * + * Need to add a folder/file watcher to the log directories to monitor file add or remove and then update the source model + */ + qDebug()<= _sdCardFiles.count()) + return QVariant(); + + const SDCardFileData &sdCardFile = _sdCardFiles[index.row()]; + switch (role) + { + case FilePathRole: return sdCardFile.filePath(); + case FileNameRole: return sdCardFile.fileName(); + case FileSizeRole: return sdCardFile.fileSize_bytes(); + +// case FilePathRole: return QString("somePath %1").arg(index.column());//sdCardFile.filePath(); +// case FileNameRole: return QString("someFilename %1").arg(index.column());//sdCardFile.fileName(); +// case FileSizeRole: return 150100;//sdCardFile.fileSize_bytes(); + + } + + return QVariant(); +} + +/*! + * \brief VSDCardFilesModel::roleNames + * Translates how to access specific properties of the data for QML from the NetworkDataRole enum + * \return (QHash) - maps enums to property names + */ +QHash VSDCardFilesModel::roleNames() const { + QHash roles; + roles[FilePathRole] = "filePath"; + roles[FileNameRole] = "fileName"; + roles[FileSizeRole] = "fileSize_bytes"; + return roles; +} + + +/*! + * \brief VSDCardFilesModel::onAddSDCardFile + * Slot that receives a request to add a new file + * \param vFileData - the new sd card file data + */ +void VSDCardFilesModel::onAddSDCardFile(const SDCardFileData &vFileData) +{ + if (!_sdCardFiles.contains(vFileData)) + { + qDebug() < +#include + +// Project +#include "main.h" +#include "VView.h" +#include "MSDCardFile.h" + + +// forward declarations +class tst_views; + +namespace View { + +/*! + * \brief The VSDCardFilesModel class + * Interface between QML and the networks + * \details Exposes networks to QML and provides an interface to connect and disconnect from those networks. + * References: https://doc.qt.io/qt-5.12/qtquick-modelviewsdata-cppmodels.html + * + */ +class VSDCardFilesModel : public QAbstractListModel +{ + Q_OBJECT + + int _interval = 1000; + + PROPERTY(QString , fileName , "") + PROPERTY(qint64 , fileSize , 0) + +public: + // Note: VIEW_DEC_CLASS(VSDCardFilesModel) requires QObject as the parent, so it's necessary to define it here + // Otherwise a VIEW_DEC_CLASS macro could allow specifying the parent class with QObject as the default + explicit VSDCardFilesModel(QAbstractListModel *parent = nullptr); + + enum SDCardFileDataRole { + FilePathRole = Qt::UserRole + 1 , + FileNameRole , + FileSizeRole , + }; + + void addSDCardFile (const SDCardFileData &vFileData); + int rowCount (const QModelIndex &parent = QModelIndex()) const; + QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const; +// void removeAllRows(); +public slots: + void doInit(); +protected: + void timerEvent(QTimerEvent *event) override; + QHash roleNames() const; + +private: + void initConnections(); + void clearSelectedNetwork(); + + QList _sdCardFiles; + +private slots: + void onAddSDCardFile(const SDCardFileData &vFileData); +// void updateList(const QString &vPathChanged); +}; +}