mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
Build changes
- Add support for embedded Linux without X, dbus, udisks, ntp, etc. - Misc minor changes
This commit is contained in:
parent
71eefa47cf
commit
5b072f3196
13 changed files with 189 additions and 222 deletions
|
@ -20,21 +20,29 @@ set(CMAKE_AUTORCC ON)
|
|||
|
||||
# Adding headers explicity so they are displayed in Qt Creator
|
||||
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h driveformatthread.h powersaveblocker.h
|
||||
downloadthread.h downloadextractthread.h acceleratedcryptographichash.h dependencies/mountutils/src/mountutils.hpp)
|
||||
downloadthread.h downloadextractthread.h dependencies/mountutils/src/mountutils.hpp)
|
||||
|
||||
# Add 3rd-party dependencies
|
||||
# Add dependencies
|
||||
if (APPLE)
|
||||
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
set(DEPENDENCIES mac/macfile.cpp mac/macfile.h mac/Info.plist dependencies/mountutils/src/darwin/functions.cpp
|
||||
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
||||
enable_language(OBJC C)
|
||||
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
set(DEPENDENCIES mac/macfile.cpp mac/macfile.h mac/Info.plist dependencies/mountutils/src/darwin/functions.cpp
|
||||
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
||||
enable_language(OBJC C)
|
||||
elseif (UNIX)
|
||||
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/udisks2api.cpp linux/udisks2api.h)
|
||||
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp)
|
||||
find_package(Qt5DBus)
|
||||
if(Qt5DBus_FOUND)
|
||||
set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h)
|
||||
set(EXTRALIBS Qt5::DBus)
|
||||
message("udisks2 support enabled")
|
||||
else()
|
||||
message("DBUS not found. Disabling udisks2 support")
|
||||
endif()
|
||||
elseif (WIN32)
|
||||
set(DEPENDENCIES dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp
|
||||
windows/winfile.cpp windows/winfile.h
|
||||
windows/rpi-imager.rc)
|
||||
set(EXTRALIBS setupapi)
|
||||
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp
|
||||
windows/winfile.cpp windows/winfile.h
|
||||
windows/rpi-imager.rc)
|
||||
set(EXTRALIBS setupapi)
|
||||
endif()
|
||||
|
||||
include_directories(BEFORE .)
|
||||
|
@ -60,10 +68,12 @@ endif()
|
|||
|
||||
set(SOURCES "main.cpp" "imagewriter.cpp" "networkaccessmanagerfactory.cpp"
|
||||
"drivelistitem.cpp" "drivelistmodel.cpp" "downloadthread.cpp" "downloadextractthread.cpp"
|
||||
"driveformatthread.cpp" "powersaveblocker.cpp" "acceleratedcryptographichash.cpp" "qml.qrc")
|
||||
"driveformatthread.cpp" "powersaveblocker.cpp" "qml.qrc")
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(Qt5 COMPONENTS Core Quick Widgets LinguistTools REQUIRED)
|
||||
find_package(Qt5 COMPONENTS Core Quick LinguistTools Svg OPTIONAL_COMPONENTS Widgets)
|
||||
if (Qt5Widgets_FOUND)
|
||||
set(EXTRALIBS ${EXTRALIBS} Qt5::Widgets)
|
||||
endif()
|
||||
|
||||
#qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
||||
qt5_add_translation(QM_FILES i18n/rpi-imager_nl.ts i18n/rpi-imager_zh_cn.ts)
|
||||
|
@ -82,6 +92,8 @@ if (WIN32)
|
|||
# Target Windows 7 (needed for drivelist module)
|
||||
add_definitions(-DWINVER=0x0601 -D_WIN32_WINNT=0x0601)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
# Bundled zlib
|
||||
add_subdirectory(dependencies/zlib-1.2.11)
|
||||
set(ZLIB_LIBRARY zlibstatic)
|
||||
|
@ -195,9 +207,7 @@ elseif(APPLE)
|
|||
find_library(CoreFoundation CoreFoundation)
|
||||
find_library(DiskArbitration DiskArbitration)
|
||||
find_library(Security Security)
|
||||
#find_package(Qt5 COMPONENTS Svg)
|
||||
#set(EXTRALIBS ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa} Qt5::Svg)
|
||||
set(EXTRALIBS ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa})
|
||||
set(EXTRALIBS ${EXTRALIBS} ${CoreFoundation} ${DiskArbitration} ${Security} ${Cocoa})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE YES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist)
|
||||
|
||||
find_program(MACDEPLOYQT "macdeployqt" PATHS "${Qt5_DIR}/../../../bin")
|
||||
|
@ -212,8 +222,7 @@ elseif(APPLE)
|
|||
else()
|
||||
find_package(CURL REQUIRED 7.32.0)
|
||||
find_package(LibArchive REQUIRED 3.2.0)
|
||||
find_package(Qt5 COMPONENTS DBus)
|
||||
set(EXTRALIBS Qt5::DBus)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
find_program(LSBLK "lsblk")
|
||||
if (NOT LSBLK)
|
||||
|
@ -232,4 +241,4 @@ else()
|
|||
endif()
|
||||
|
||||
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Widgets ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
||||
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
*/
|
||||
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
typedef QCryptographicHash AcceleratedCryptographicHash;
|
||||
#else
|
||||
|
||||
#include "openssl/sha.h"
|
||||
|
||||
class AcceleratedCryptographicHash
|
||||
|
@ -22,4 +27,5 @@ protected:
|
|||
SHA256_CTX _sha256;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // ACCELERATEDCRYPTOGRAPHICHASH_H
|
||||
|
|
3
config.h
3
config.h
|
@ -10,6 +10,9 @@
|
|||
/* Repository URL */
|
||||
#define OSLIST_URL "https://downloads.raspberrypi.org/os_list_imagingutility.json"
|
||||
|
||||
/* Time synchronization URL (only used on eglfs QPA platform, URL must be HTTP) */
|
||||
#define TIME_URL "http://downloads.raspberrypi.org/os_list_imagingutility.json?time_synchronization"
|
||||
|
||||
/* Hash algorithm for verifying (uncompressed image) checksum */
|
||||
#define OSLIST_HASH_ALGORITHM QCryptographicHash::Sha256
|
||||
|
||||
|
|
36
dependencies/mountutils/example/eject.js
vendored
36
dependencies/mountutils/example/eject.js
vendored
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const mountUtils = require('..');
|
||||
|
||||
let argv = process.argv.slice(2);
|
||||
let disk = argv.shift();
|
||||
|
||||
if (!disk) {
|
||||
console.error(`Usage: node example/eject <disk>`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.env.MOUNTUTILS_DEBUG = true;
|
||||
|
||||
console.log('Ejecting', disk, '...');
|
||||
|
||||
mountUtils.eject(disk, function(error) {
|
||||
console.log(error || 'OK');
|
||||
});
|
36
dependencies/mountutils/example/unmount.js
vendored
36
dependencies/mountutils/example/unmount.js
vendored
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const mountUtils = require('..');
|
||||
|
||||
let argv = process.argv.slice(2);
|
||||
let disk = argv.shift();
|
||||
|
||||
if (!disk) {
|
||||
console.error(`Usage: node example/unmount <disk>`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.env.MOUNTUTILS_DEBUG = true;
|
||||
|
||||
console.log('Unmounting', disk, '...');
|
||||
|
||||
mountUtils.unmountDisk(disk, function(error) {
|
||||
console.log(error || 'OK');
|
||||
});
|
106
dependencies/mountutils/tests/mountutils.spec.js
vendored
106
dependencies/mountutils/tests/mountutils.spec.js
vendored
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const chai = require('chai');
|
||||
const mountutils = require('../');
|
||||
|
||||
describe('MountUtils', function() {
|
||||
|
||||
describe('.unmountDisk()', function() {
|
||||
|
||||
it('should be a function', function() {
|
||||
chai.expect(mountutils.unmountDisk).to.be.a('function');
|
||||
});
|
||||
|
||||
context('missing / wrong arguments', function() {
|
||||
|
||||
specify('throws on missing device', function() {
|
||||
chai.expect(function() {
|
||||
mountutils.unmountDisk(null, function() {});
|
||||
}).to.throw(/must be a string/i);
|
||||
});
|
||||
|
||||
specify('throws on missing callback', function() {
|
||||
chai.expect(function() {
|
||||
mountutils.unmountDisk('novalue');
|
||||
}).to.throw(/must be a function/i);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
context('invalid device', function() {
|
||||
|
||||
specify('device is a directory', function( done ) {
|
||||
mountutils.unmountDisk( __dirname, function( error ) {
|
||||
chai.expect(error.message).to.match(/Unmount failed/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify('device is an empty string', function( done ) {
|
||||
mountutils.unmountDisk( '', function( error ) {
|
||||
chai.expect(error.message).to.match(/Unmount failed/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('.eject()', function() {
|
||||
|
||||
it('should be a function', function() {
|
||||
chai.expect(mountutils.eject).to.be.a('function');
|
||||
});
|
||||
|
||||
context('missing / wrong arguments', function() {
|
||||
|
||||
specify('throws on missing device', function() {
|
||||
chai.expect(function() {
|
||||
mountutils.eject(null, function() {});
|
||||
}).to.throw(/must be a string/i);
|
||||
});
|
||||
|
||||
specify('throws on missing callback', function() {
|
||||
chai.expect(function() {
|
||||
mountutils.eject('novalue');
|
||||
}).to.throw(/must be a function/i);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
context('invalid device', function() {
|
||||
|
||||
specify('device is a directory', function( done ) {
|
||||
mountutils.eject( __dirname, function( error ) {
|
||||
chai.expect(error.message).to.match(/Eject failed/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify('device is an empty string', function( done ) {
|
||||
mountutils.eject( '', function( error ) {
|
||||
chai.expect(error.message).to.match(/Eject failed/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -178,6 +178,7 @@ bool DownloadThread::_openAndPrepareDevice()
|
|||
if (!_file.open(QIODevice::ReadWrite | QIODevice::Unbuffered))
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifndef QT_NO_DBUS
|
||||
/* Opening device directly did not work, ask udisks2 to do it for us,
|
||||
* if necessary prompting for authorization */
|
||||
UDisks2Api udisks;
|
||||
|
@ -187,11 +188,10 @@ bool DownloadThread::_openAndPrepareDevice()
|
|||
_file.open(fd, QIODevice::ReadWrite | QIODevice::Unbuffered, QFileDevice::AutoCloseHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
{
|
||||
emit error(tr("Cannot open storage device '%1'.").arg(QString(_filename)));
|
||||
return false;
|
||||
#ifdef Q_OS_LINUX
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ void DriveFormatThread::run()
|
|||
{
|
||||
/* Not running as root, try to outsource formatting to udisks2 */
|
||||
|
||||
#ifndef QT_NO_DBUS
|
||||
UDisks2Api udisks2;
|
||||
if (udisks2.formatDrive(_device))
|
||||
{
|
||||
|
@ -141,8 +142,11 @@ void DriveFormatThread::run()
|
|||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
emit error(tr("Error formatting (through udisks2)"));
|
||||
#ifndef QT_NO_DBUS
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -14,11 +14,19 @@
|
|||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QProcess>
|
||||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
#include <QStorageInfo>
|
||||
#include <QWindow>
|
||||
#include <QGuiApplication>
|
||||
#include <QNetworkInterface>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#ifndef QT_NO_WIDGETS
|
||||
#include <QFileDialog>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
|
@ -27,10 +35,19 @@
|
|||
|
||||
ImageWriter::ImageWriter(QObject *parent)
|
||||
: QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0),
|
||||
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false)
|
||||
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false),
|
||||
_embeddedMode(false), _online(false)
|
||||
{
|
||||
connect(&_polltimer, SIGNAL(timeout()), SLOT(pollProgress()));
|
||||
|
||||
QString platform = QGuiApplication::platformName();
|
||||
if (platform == "eglfs" || platform == "wayland" || platform == "linuxfb")
|
||||
{
|
||||
_embeddedMode = true;
|
||||
connect(&_networkchecktimer, SIGNAL(timeout()), SLOT(pollNetwork()));
|
||||
_networkchecktimer.start(100);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QProcess *p = new QProcess(this);
|
||||
p->start("net stop ShellHWDetection");
|
||||
|
@ -63,7 +80,7 @@ ImageWriter::ImageWriter(QObject *parent)
|
|||
}
|
||||
|
||||
_settings.beginGroup("caching");
|
||||
_cachingEnabled = _settings.value("enabled", IMAGEWRITER_ENABLE_CACHE_DEFAULT).toBool();
|
||||
_cachingEnabled = !_embeddedMode && _settings.value("enabled", IMAGEWRITER_ENABLE_CACHE_DEFAULT).toBool();
|
||||
_cachedFileHash = _settings.value("lastDownloadSHA256").toByteArray();
|
||||
_cacheFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+QDir::separator()+"lastdownload.cache";
|
||||
if (!_cachedFileHash.isEmpty())
|
||||
|
@ -377,6 +394,7 @@ void ImageWriter::onFinalizing()
|
|||
|
||||
void ImageWriter::openFileDialog()
|
||||
{
|
||||
#ifndef QT_NO_WIDGETS
|
||||
QFileDialog *fd = new QFileDialog(nullptr, tr("Select image"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation),
|
||||
"Image files (*.img *.zip *.gz *.xz);;All files (*.*)");
|
||||
|
@ -394,6 +412,7 @@ void ImageWriter::openFileDialog()
|
|||
}
|
||||
|
||||
fd->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageWriter::onFileSelected(QString filename)
|
||||
|
@ -441,6 +460,66 @@ void ImageWriter::_parseCompressedFile()
|
|||
qDebug() << "Parsed .zip file containing" << numFiles << "files, uncompressed size:" << _extrLen;
|
||||
}
|
||||
|
||||
bool ImageWriter::isOnline()
|
||||
{
|
||||
return _online || !_embeddedMode;
|
||||
}
|
||||
|
||||
void ImageWriter::pollNetwork()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
/* Check if we have an IP-address other than localhost */
|
||||
QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
|
||||
|
||||
foreach (QHostAddress a, addresses)
|
||||
{
|
||||
if (!a.isLoopback() && a.scopeId().isEmpty())
|
||||
{
|
||||
/* Not a loopback or IPv6 link-local address, so online */
|
||||
_online = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_online)
|
||||
{
|
||||
_networkchecktimer.stop();
|
||||
qDebug() << "Network online. Synchronizing time.";
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
connect(manager, SIGNAL(finished(QNetworkReply*)), SLOT(onTimeSyncReply(QNetworkReply*)));
|
||||
manager->head(QNetworkRequest(QUrl(TIME_URL)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
if (reply->hasRawHeader("Date"))
|
||||
{
|
||||
QDateTime dt = QDateTime::fromString(reply->rawHeader("Date"), Qt::RFC2822Date);
|
||||
qDebug() << "Received current time from server:" << dt;
|
||||
struct timeval tv = {
|
||||
(time_t) dt.toSecsSinceEpoch(), 0
|
||||
};
|
||||
::settimeofday(&tv, NULL);
|
||||
|
||||
emit networkOnline();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: try again later?
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ImageWriter::isEmbeddedMode()
|
||||
{
|
||||
return _embeddedMode;
|
||||
}
|
||||
|
||||
void MountUtilsLog(std::string msg) {
|
||||
qDebug() << "mountutils:" << msg.c_str();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
class QQmlApplicationEngine;
|
||||
class DownloadThread;
|
||||
class QNetworkReply;
|
||||
|
||||
class ImageWriter : public QObject
|
||||
{
|
||||
|
@ -71,6 +72,11 @@ public:
|
|||
/* Return filename part of URL set */
|
||||
Q_INVOKABLE QString srcFileName();
|
||||
|
||||
/* Returns true if online */
|
||||
Q_INVOKABLE bool isOnline();
|
||||
|
||||
Q_INVOKABLE bool isEmbeddedMode();
|
||||
|
||||
signals:
|
||||
/* We are emiting signals with QVariant as parameters because QML likes it that way */
|
||||
|
||||
|
@ -81,16 +87,19 @@ signals:
|
|||
void fileSelected(QVariant filename);
|
||||
void cancelled();
|
||||
void finalizing();
|
||||
void networkOnline();
|
||||
|
||||
protected slots:
|
||||
|
||||
void pollProgress();
|
||||
void pollNetwork();
|
||||
void onSuccess();
|
||||
void onError(QString msg);
|
||||
void onFileSelected(QString filename);
|
||||
void onCancelled();
|
||||
void onCacheFileUpdated(QByteArray sha256);
|
||||
void onFinalizing();
|
||||
void onTimeSyncReply(QNetworkReply *reply);
|
||||
|
||||
protected:
|
||||
QUrl _src, _repo;
|
||||
|
@ -99,10 +108,10 @@ protected:
|
|||
quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow;
|
||||
DriveListModel _drivelist;
|
||||
QQmlApplicationEngine *_engine;
|
||||
QTimer _polltimer;
|
||||
QTimer _polltimer, _networkchecktimer;
|
||||
PowerSaveBlocker _powersave;
|
||||
DownloadThread *_thread;
|
||||
bool _verifyEnabled, _multipleFilesInZip, _cachingEnabled;
|
||||
bool _verifyEnabled, _multipleFilesInZip, _cachingEnabled, _embeddedMode, _online;
|
||||
QSettings _settings;
|
||||
|
||||
void _parseCompressedFile();
|
||||
|
|
|
@ -103,6 +103,12 @@ namespace Drivelist
|
|||
bdev["vendor"].toString().trimmed(),
|
||||
bdev["model"].toString().trimmed()
|
||||
};
|
||||
if (name == "/dev/mmcblk0")
|
||||
{
|
||||
dp.removeAll("");
|
||||
if (dp.empty())
|
||||
dp.append(QObject::tr("Internal SD card reader"));
|
||||
}
|
||||
|
||||
QString mp = bdev["mountpoint"].toString();
|
||||
if (!mp.isEmpty())
|
||||
|
|
13
main.cpp
13
main.cpp
|
@ -13,11 +13,13 @@
|
|||
#include "imagewriter.h"
|
||||
#include "drivelistmodel.h"
|
||||
#include "networkaccessmanagerfactory.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QMessageLogContext>
|
||||
#include <QQuickWindow>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
#ifndef QT_NO_WIDGETS
|
||||
#include <QtWidgets/QApplication>
|
||||
#endif
|
||||
|
||||
static QTextStream cerr(stderr);
|
||||
|
||||
|
@ -29,12 +31,16 @@ static void consoleMsgHandler(QtMsgType, const QMessageLogContext &, const QStri
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#ifdef Q_OS_WIN
|
||||
// prefer ANGLE (DirectX) over desktop OpenGL
|
||||
QApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
#ifdef QT_NO_WIDGETS
|
||||
QGuiApplication app(argc, argv);
|
||||
#else
|
||||
QApplication app(argc, argv);
|
||||
#endif
|
||||
app.setOrganizationName("Raspberry Pi");
|
||||
app.setOrganizationDomain("raspberrypi.org");
|
||||
app.setApplicationName("Imager");
|
||||
|
@ -146,6 +152,7 @@ int main(int argc, char *argv[])
|
|||
qmlwindow->connect(&imageWriter, SIGNAL(fileSelected(QVariant)), qmlwindow, SLOT(onFileSelected(QVariant)));
|
||||
qmlwindow->connect(&imageWriter, SIGNAL(cancelled()), qmlwindow, SLOT(onCancelled()));
|
||||
qmlwindow->connect(&imageWriter, SIGNAL(finalizing()), qmlwindow, SLOT(onFinalizing()));
|
||||
qmlwindow->connect(&imageWriter, SIGNAL(networkOnline()), qmlwindow, SLOT(fetchOSlist()));
|
||||
|
||||
int rc = app.exec();
|
||||
return rc;
|
||||
|
|
50
main.qml
50
main.qml
|
@ -36,6 +36,16 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.Quit
|
||||
context: Qt.ApplicationShortcut
|
||||
onActivated: {
|
||||
if (!progressBar.visible) {
|
||||
Qt.quit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: bg
|
||||
spacing: 0
|
||||
|
@ -358,17 +368,9 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
httpRequest(imageWriter.constantOsListUrl(), function (x) {
|
||||
var o = JSON.parse(x.responseText)
|
||||
if (!"os_list" in o) {
|
||||
onError(qsTr("Error parsing os_list.json"))
|
||||
return;
|
||||
}
|
||||
var oslist = o["os_list"]
|
||||
for (var i in oslist) {
|
||||
osmodel.insert(osmodel.count-2, oslist[i])
|
||||
}
|
||||
})
|
||||
if (imageWriter.isOnline()) {
|
||||
fetchOSlist();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,7 +527,13 @@ ApplicationWindow {
|
|||
osswipeview.setCurrentIndex(1)
|
||||
}
|
||||
} else if (url == "") {
|
||||
imageWriter.openFileDialog()
|
||||
if (!imageWriter.isEmbeddedMode()) {
|
||||
imageWriter.openFileDialog()
|
||||
}
|
||||
else {
|
||||
// FIXME: provide QML file dialog
|
||||
onError("Using custom images is not implemented on this platform yet.")
|
||||
}
|
||||
} else {
|
||||
imageWriter.setSrc(url, image_download_size, extract_size, typeof(extract_sha256) != "undefined" ? extract_sha256 : "", typeof(contains_multiple_files) != "undefined" ? contains_multiple_files : false)
|
||||
osbutton.text = name
|
||||
|
@ -787,7 +795,7 @@ ApplicationWindow {
|
|||
Material.foreground: "#ffffff"
|
||||
Material.background: "#c51a4a"
|
||||
font.family: roboto.name
|
||||
visible: false
|
||||
visible: imageWriter.isEmbeddedMode()
|
||||
}
|
||||
|
||||
Button {
|
||||
|
@ -795,7 +803,7 @@ ApplicationWindow {
|
|||
text: qsTr("CONTINUE")
|
||||
onClicked: {
|
||||
msgpopup.close()
|
||||
quitbutton.visible = false
|
||||
quitbutton.visible = imageWriter.isEmbeddedMode()
|
||||
}
|
||||
Material.foreground: "#ffffff"
|
||||
Material.background: "#c51a4a"
|
||||
|
@ -931,4 +939,18 @@ ApplicationWindow {
|
|||
function onFinalizing() {
|
||||
progressText.text = qsTr("Finalizing...")
|
||||
}
|
||||
|
||||
function fetchOSlist() {
|
||||
httpRequest(imageWriter.constantOsListUrl(), function (x) {
|
||||
var o = JSON.parse(x.responseText)
|
||||
if (!"os_list" in o) {
|
||||
onError(qsTr("Error parsing os_list.json"))
|
||||
return;
|
||||
}
|
||||
var oslist = o["os_list"]
|
||||
for (var i in oslist) {
|
||||
osmodel.insert(osmodel.count-2, oslist[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue