Skip to content

Commit fb126b8

Browse files
committed
feat: added selection of drive for restoring
Signed-off-by: Evzen Gasta <evzen.ml@seznam.cz>
1 parent 0965df4 commit fb126b8

File tree

7 files changed

+316
-56
lines changed

7 files changed

+316
-56
lines changed

src/app/crashhandler.cpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,23 @@
2626
# include <dbghelp.h>
2727

2828
void printStack(void) {
29-
HANDLE process = GetCurrentProcess();
30-
SymInitialize( process, NULL, TRUE );
29+
HANDLE process = GetCurrentProcess();
30+
SymInitialize( process, NULL, TRUE );
3131

32-
void *stack[64];
33-
unsigned short frames = CaptureStackBackTrace( 0, 64, stack, NULL );
32+
void *stack[64];
33+
unsigned short frames = CaptureStackBackTrace( 0, 64, stack, NULL );
3434

35-
SYMBOL_INFO *symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
36-
symbol->MaxNameLen = 255;
37-
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
35+
SYMBOL_INFO *symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
36+
symbol->MaxNameLen = 255;
37+
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
3838

39-
mCritical() << "Backtrace:";
40-
for(int i = 0; i < frames; i++) {
41-
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
42-
mCritical() << '\t' << frames - i - 1 << ':' << symbol->Name << (void*)symbol->Address;
43-
}
39+
mCritical() << "Backtrace:";
40+
for(int i = 0; i < frames; i++) {
41+
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
42+
mCritical() << '\t' << frames - i - 1 << ':' << symbol->Name << (void*)symbol->Address;
43+
}
4444

45-
free(symbol);
45+
free(symbol);
4646
}
4747

4848
LONG faultHandler(struct _EXCEPTION_POINTERS *info) {
@@ -79,4 +79,3 @@ void CrashHandler::install() {
7979
}
8080

8181
#endif // _WIN32
82-

src/app/drivemanager.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,178 @@ void Drive::setRestoreStatus(Drive::RestoreStatus o)
343343
emit restoreStatusChanged();
344344
}
345345
}
346+
347+
RestoreableDriveManager::RestoreableDriveManager(QObject *parent)
348+
: QSortFilterProxyModel(parent)
349+
{
350+
setSourceModel(DriveManager::instance());
351+
352+
connect(DriveManager::instance(), &DriveManager::drivesChanged, this, &RestoreableDriveManager::onSourceModelChanged);
353+
354+
// Connect to existing drives
355+
connectToDrives();
356+
357+
if (rowCount() > 0) {
358+
m_selectedIndex = 0;
359+
}
360+
}
361+
362+
void RestoreableDriveManager::connectToDrives()
363+
{
364+
DriveManager *dm = DriveManager::instance();
365+
for (int i = 0; i < dm->rowCount(); i++) {
366+
QModelIndex idx = dm->index(i, 0);
367+
Drive *drive = qvariant_cast<Drive *>(dm->data(idx, Qt::UserRole + 1));
368+
if (drive) {
369+
// Use unique connection to avoid duplicates
370+
connect(drive, &Drive::restoreStatusChanged, this, &RestoreableDriveManager::onDriveRestoreStatusChanged, Qt::UniqueConnection);
371+
}
372+
}
373+
}
374+
375+
void RestoreableDriveManager::onDriveRestoreStatusChanged()
376+
{
377+
// Store the previously selected drive
378+
Drive *previouslySelected = selected();
379+
380+
// Invalidate filter to update which drives are shown
381+
invalidateFilter();
382+
emit lengthChanged();
383+
384+
// Check if the previously selected drive is still in the filtered list
385+
if (previouslySelected) {
386+
bool stillInList = false;
387+
for (int i = 0; i < rowCount(); i++) {
388+
QModelIndex idx = index(i, 0);
389+
Drive *drive = qvariant_cast<Drive *>(data(idx, Qt::UserRole + 1));
390+
if (drive == previouslySelected) {
391+
stillInList = true;
392+
if (m_selectedIndex != i) {
393+
m_selectedIndex = i;
394+
emit selectedChanged();
395+
}
396+
break;
397+
}
398+
}
399+
400+
// If the previously selected drive is no longer in the list, select a new one
401+
if (!stillInList) {
402+
if (rowCount() > 0) {
403+
m_selectedIndex = 0;
404+
} else {
405+
m_selectedIndex = -1;
406+
}
407+
emit selectedChanged();
408+
}
409+
} else {
410+
// No previous selection - select first drive if available
411+
if (rowCount() > 0) {
412+
m_selectedIndex = 0;
413+
emit selectedChanged();
414+
}
415+
}
416+
}
417+
418+
bool RestoreableDriveManager::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
419+
{
420+
Q_UNUSED(source_parent)
421+
422+
DriveManager *dm = DriveManager::instance();
423+
if (source_row < 0 || source_row >= dm->rowCount())
424+
return false;
425+
426+
QModelIndex idx = dm->index(source_row, 0);
427+
Drive *drive = qvariant_cast<Drive *>(dm->data(idx, Qt::UserRole + 1));
428+
429+
if (drive && drive->restoreStatus() == Drive::CONTAINS_LIVE)
430+
return true;
431+
432+
return false;
433+
}
434+
435+
QHash<int, QByteArray> RestoreableDriveManager::roleNames() const
436+
{
437+
QHash<int, QByteArray> ret;
438+
ret.insert(Qt::UserRole + 1, "drive");
439+
ret.insert(Qt::UserRole + 2, "display");
440+
ret.insert(Qt::DisplayRole, "name");
441+
return ret;
442+
}
443+
444+
QVariant RestoreableDriveManager::data(const QModelIndex &index, int role) const
445+
{
446+
if (!index.isValid())
447+
return QVariant();
448+
449+
QModelIndex sourceIndex = mapToSource(index);
450+
DriveManager *dm = DriveManager::instance();
451+
452+
if (role == Qt::UserRole + 1)
453+
return dm->data(sourceIndex, Qt::UserRole + 1);
454+
else if (role == Qt::UserRole + 2 || role == Qt::DisplayRole) {
455+
Drive *drive = qvariant_cast<Drive *>(dm->data(sourceIndex, Qt::UserRole + 1));
456+
if (drive)
457+
return drive->name();
458+
}
459+
460+
return QVariant();
461+
}
462+
463+
Drive *RestoreableDriveManager::selected() const
464+
{
465+
if (m_selectedIndex >= 0 && m_selectedIndex < rowCount()) {
466+
QModelIndex idx = index(m_selectedIndex, 0);
467+
return qvariant_cast<Drive *>(data(idx, Qt::UserRole + 1));
468+
}
469+
return nullptr;
470+
}
471+
472+
int RestoreableDriveManager::selectedIndex() const
473+
{
474+
return m_selectedIndex;
475+
}
476+
477+
void RestoreableDriveManager::setSelectedIndex(int index)
478+
{
479+
if (m_selectedIndex != index && index >= 0 && index < rowCount()) {
480+
m_selectedIndex = index;
481+
emit selectedChanged();
482+
}
483+
}
484+
485+
int RestoreableDriveManager::length() const
486+
{
487+
return rowCount();
488+
}
489+
490+
void RestoreableDriveManager::onSourceModelChanged()
491+
{
492+
// Connect to any new drives
493+
connectToDrives();
494+
495+
// Remember previous state
496+
int previousCount = rowCount();
497+
Drive *previousSelected = selected();
498+
499+
invalidateFilter();
500+
501+
int newCount = rowCount();
502+
503+
// Always emit length changed
504+
emit lengthChanged();
505+
506+
// Reset selection if out of bounds
507+
if (m_selectedIndex >= newCount) {
508+
m_selectedIndex = newCount > 0 ? 0 : -1;
509+
}
510+
511+
// If there are restoreable drives and nothing is selected, select the first one
512+
if (m_selectedIndex < 0 && newCount > 0) {
513+
m_selectedIndex = 0;
514+
}
515+
516+
// Emit selectedChanged if the selected drive changed
517+
if (selected() != previousSelected) {
518+
emit selectedChanged();
519+
}
520+
}

src/app/drivemanager.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@
2222

2323
#include <QAbstractListModel>
2424
#include <QDebug>
25+
#include <QSortFilterProxyModel>
2526

2627
#include "releasemanager.h"
2728

2829
class DriveManager;
2930
class DriveProvider;
3031
class Drive;
3132
class UdisksDrive;
33+
class RestoreableDriveManager;
3234

3335
/**
3436
* @brief The DriveManager class
@@ -196,4 +198,47 @@ public slots:
196198
bool m_delayedWrite{false};
197199
};
198200

201+
/**
202+
* @brief The RestoreableDriveManager class
203+
*
204+
* A proxy model that filters drives to only show those containing live USB systems.
205+
*
206+
* @property selected the currently selected drive
207+
* @property selectedIndex the index of the currently selected drive
208+
* @property length count of the filtered (restoreable) drives
209+
*/
210+
class RestoreableDriveManager : public QSortFilterProxyModel
211+
{
212+
Q_OBJECT
213+
Q_PROPERTY(Drive *selected READ selected NOTIFY selectedChanged)
214+
Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedChanged)
215+
Q_PROPERTY(int length READ length NOTIFY lengthChanged)
216+
public:
217+
explicit RestoreableDriveManager(QObject *parent = nullptr);
218+
219+
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
220+
221+
QHash<int, QByteArray> roleNames() const override;
222+
Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
223+
224+
Drive *selected() const;
225+
int selectedIndex() const;
226+
void setSelectedIndex(int index);
227+
228+
int length() const;
229+
230+
signals:
231+
void selectedChanged();
232+
void lengthChanged();
233+
234+
private slots:
235+
void onSourceModelChanged();
236+
void onDriveRestoreStatusChanged();
237+
238+
private:
239+
void connectToDrives();
240+
241+
int m_selectedIndex{0};
242+
};
243+
199244
#endif // DRIVEMANAGER_H

src/app/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ int main(int argc, char **argv)
6464

6565
engine.rootContext()->setContextProperty("downloadManager", DownloadManager::instance());
6666
engine.rootContext()->setContextProperty("drives", DriveManager::instance());
67+
engine.rootContext()->setContextProperty("restoreableDrives", new RestoreableDriveManager());
6768
engine.rootContext()->setContextProperty("portalFileDialog", new PortalFileDialog(&app));
6869
engine.rootContext()->setContextProperty("mediawriterVersion", MEDIAWRITER_VERSION);
6970
engine.rootContext()->setContextProperty("releases", new ReleaseManager());

src/app/qml/MainPage.qml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,20 @@ Page {
4646

4747
QQC2.RadioButton {
4848
id: restoreRadio
49-
visible: drives.lastRestoreable
50-
text: drives.lastRestoreable ? qsTr("Restore <b>%1</b>").arg(drives.lastRestoreable.name) : ""
49+
visible: restoreableDrives.length > 0
50+
text: {
51+
if (restoreableDrives.length === 0)
52+
return ""
53+
else if (restoreableDrives.length === 1 && restoreableDrives.selected)
54+
return qsTr("Restore <b>%1</b>").arg(restoreableDrives.selected.name)
55+
else if (restoreableDrives.length > 1)
56+
return qsTr("Restore a USB drive (%1 available)").arg(restoreableDrives.length)
57+
else
58+
return qsTr("Restore a USB drive")
59+
}
5160
onClicked: {
5261
selectedOption = Units.MainSelect.Restore
5362
}
54-
55-
Connections {
56-
target: drives
57-
function onLastRestoreableChanged() {
58-
if (drives.lastRestoreable != null && !restoreRadio.visible)
59-
restoreRadio.visible = true
60-
if (!drives.lastRestoreable)
61-
restoreRadio.visible = false
62-
}
63-
}
6463
}
6564

6665
// HACK: enforces all the items above to move up and make smaller

0 commit comments

Comments
 (0)