Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions src/app/drivemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,178 @@ void Drive::setRestoreStatus(Drive::RestoreStatus o)
emit restoreStatusChanged();
}
}

RestoreableDriveManager::RestoreableDriveManager(QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(DriveManager::instance());

connect(DriveManager::instance(), &DriveManager::drivesChanged, this, &RestoreableDriveManager::onSourceModelChanged);

// Connect to existing drives
connectToDrives();

if (rowCount() > 0) {
m_selectedIndex = 0;
}
}

void RestoreableDriveManager::connectToDrives()
{
DriveManager *dm = DriveManager::instance();
for (int i = 0; i < dm->rowCount(); i++) {
QModelIndex idx = dm->index(i, 0);
Drive *drive = qvariant_cast<Drive *>(dm->data(idx, Qt::UserRole + 1));
if (drive) {
// Use unique connection to avoid duplicates
connect(drive, &Drive::restoreStatusChanged, this, &RestoreableDriveManager::onDriveRestoreStatusChanged, Qt::UniqueConnection);
}
}
}

void RestoreableDriveManager::onDriveRestoreStatusChanged()
{
// Store the previously selected drive
Drive *previouslySelected = selected();

// Invalidate filter to update which drives are shown
invalidateFilter();
emit lengthChanged();

// Check if the previously selected drive is still in the filtered list
if (previouslySelected) {
bool stillInList = false;
for (int i = 0; i < rowCount(); i++) {
QModelIndex idx = index(i, 0);
Drive *drive = qvariant_cast<Drive *>(data(idx, Qt::UserRole + 1));
if (drive == previouslySelected) {
stillInList = true;
if (m_selectedIndex != i) {
m_selectedIndex = i;
emit selectedChanged();
}
break;
}
}

// If the previously selected drive is no longer in the list, select a new one
if (!stillInList) {
if (rowCount() > 0) {
m_selectedIndex = 0;
} else {
m_selectedIndex = -1;
}
emit selectedChanged();
}
} else {
// No previous selection - select first drive if available
if (rowCount() > 0) {
m_selectedIndex = 0;
emit selectedChanged();
}
}
}

bool RestoreableDriveManager::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
Q_UNUSED(source_parent)

DriveManager *dm = DriveManager::instance();
if (source_row < 0 || source_row >= dm->rowCount())
return false;

QModelIndex idx = dm->index(source_row, 0);
Drive *drive = qvariant_cast<Drive *>(dm->data(idx, Qt::UserRole + 1));

if (drive && drive->restoreStatus() == Drive::CONTAINS_LIVE)
return true;

return false;
}

QHash<int, QByteArray> RestoreableDriveManager::roleNames() const
{
QHash<int, QByteArray> ret;
ret.insert(Qt::UserRole + 1, "drive");
ret.insert(Qt::UserRole + 2, "display");
ret.insert(Qt::DisplayRole, "name");
return ret;
}

QVariant RestoreableDriveManager::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

QModelIndex sourceIndex = mapToSource(index);
DriveManager *dm = DriveManager::instance();

if (role == Qt::UserRole + 1)
return dm->data(sourceIndex, Qt::UserRole + 1);
else if (role == Qt::UserRole + 2 || role == Qt::DisplayRole) {
Drive *drive = qvariant_cast<Drive *>(dm->data(sourceIndex, Qt::UserRole + 1));
if (drive)
return drive->name();
}

return QVariant();
}

Drive *RestoreableDriveManager::selected() const
{
if (m_selectedIndex >= 0 && m_selectedIndex < rowCount()) {
QModelIndex idx = index(m_selectedIndex, 0);
return qvariant_cast<Drive *>(data(idx, Qt::UserRole + 1));
}
return nullptr;
}

int RestoreableDriveManager::selectedIndex() const
{
return m_selectedIndex;
}

void RestoreableDriveManager::setSelectedIndex(int index)
{
if (m_selectedIndex != index && index >= 0 && index < rowCount()) {
m_selectedIndex = index;
emit selectedChanged();
}
}

int RestoreableDriveManager::length() const
{
return rowCount();
}

void RestoreableDriveManager::onSourceModelChanged()
{
// Connect to any new drives
connectToDrives();

// Remember previous state
int previousCount = rowCount();
Drive *previousSelected = selected();

invalidateFilter();

int newCount = rowCount();

// Always emit length changed
emit lengthChanged();

// Reset selection if out of bounds
if (m_selectedIndex >= newCount) {
m_selectedIndex = newCount > 0 ? 0 : -1;
}

// If there are restoreable drives and nothing is selected, select the first one
if (m_selectedIndex < 0 && newCount > 0) {
m_selectedIndex = 0;
}

// Emit selectedChanged if the selected drive changed
if (selected() != previousSelected) {
emit selectedChanged();
}
}
45 changes: 45 additions & 0 deletions src/app/drivemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@

#include <QAbstractListModel>
#include <QDebug>
#include <QSortFilterProxyModel>

#include "releasemanager.h"

class DriveManager;
class DriveProvider;
class Drive;
class UdisksDrive;
class RestoreableDriveManager;

/**
* @brief The DriveManager class
Expand Down Expand Up @@ -196,4 +198,47 @@ public slots:
bool m_delayedWrite{false};
};

/**
* @brief The RestoreableDriveManager class
*
* A proxy model that filters drives to only show those containing live USB systems.
*
* @property selected the currently selected drive
* @property selectedIndex the index of the currently selected drive
* @property length count of the filtered (restoreable) drives
*/
class RestoreableDriveManager : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(Drive *selected READ selected NOTIFY selectedChanged)
Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedChanged)
Q_PROPERTY(int length READ length NOTIFY lengthChanged)
public:
explicit RestoreableDriveManager(QObject *parent = nullptr);

bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;

QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

Drive *selected() const;
int selectedIndex() const;
void setSelectedIndex(int index);

int length() const;

signals:
void selectedChanged();
void lengthChanged();

private slots:
void onSourceModelChanged();
void onDriveRestoreStatusChanged();

private:
void connectToDrives();

int m_selectedIndex{0};
};

#endif // DRIVEMANAGER_H
1 change: 1 addition & 0 deletions src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ int main(int argc, char **argv)

engine.rootContext()->setContextProperty("downloadManager", DownloadManager::instance());
engine.rootContext()->setContextProperty("drives", DriveManager::instance());
engine.rootContext()->setContextProperty("restoreableDrives", new RestoreableDriveManager());
engine.rootContext()->setContextProperty("portalFileDialog", new PortalFileDialog(&app));
engine.rootContext()->setContextProperty("mediawriterVersion", MEDIAWRITER_VERSION);
engine.rootContext()->setContextProperty("releases", new ReleaseManager());
Expand Down
23 changes: 11 additions & 12 deletions src/app/qml/MainPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,20 @@ Page {

QQC2.RadioButton {
id: restoreRadio
visible: drives.lastRestoreable
text: drives.lastRestoreable ? qsTr("Restore <b>%1</b>").arg(drives.lastRestoreable.name) : ""
visible: restoreableDrives.length > 0
text: {
if (restoreableDrives.length === 0)
return ""
else if (restoreableDrives.length === 1 && restoreableDrives.selected)
return qsTr("Restore <b>%1</b>").arg(restoreableDrives.selected.name)
else if (restoreableDrives.length > 1)
return qsTr("Restore a USB drive (%1 available)").arg(restoreableDrives.length)
else
return qsTr("Restore a USB drive")
}
onClicked: {
selectedOption = Units.MainSelect.Restore
}

Connections {
target: drives
function onLastRestoreableChanged() {
if (drives.lastRestoreable != null && !restoreRadio.visible)
restoreRadio.visible = true
if (!drives.lastRestoreable)
restoreRadio.visible = false
}
}
}

// HACK: enforces all the items above to move up and make smaller
Expand Down
Loading