Linux embedded: misc improvements
- Allow static build - Use .svg icons - Linux Embedded lacks normal "open file dialog". So simply scan files in root folder of USB stick and return list. - Change QProcess::execute(command) calls to QProcess::execute(command, args) calls to silence Qt 5.15.0 depreciation warning.
|
@ -240,5 +240,12 @@ else()
|
||||||
install(FILES linux/rpi-imager.desktop DESTINATION share/applications)
|
install(FILES linux/rpi-imager.desktop DESTINATION share/applications)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
get_target_property(QT_TARGET_TYPE Qt5::Core TYPE)
|
||||||
|
if(${QT_TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
|
||||||
|
find_package(Qt5QmlImportScanner REQUIRED)
|
||||||
|
qt5_import_qml_plugins(${PROJECT_NAME})
|
||||||
|
qt5_import_plugins(${PROJECT_NAME} INCLUDE Qt5::QSvgPlugin)
|
||||||
|
endif()
|
||||||
|
|
||||||
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
||||||
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick Qt5::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS})
|
||||||
|
|
|
@ -186,7 +186,7 @@ void DriveFormatThread::run()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc.execute("partprobe");
|
proc.execute("partprobe", QStringList() );
|
||||||
|
|
||||||
args.clear();
|
args.clear();
|
||||||
args << fatpartition;
|
args << fatpartition;
|
||||||
|
|
Before Width: | Height: | Size: 493 B |
6
icons/ic_build_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 37.832031 31.582031 L 22.582031 16.332031 C 24.082031 12.5 23.25 7.917969 20.167969 4.832031 C 16.832031 1.5 11.832031 0.832031 7.832031 2.75 L 15.082031 10 L 10 15.082031 L 2.75 7.832031 C 0.832031 11.832031 1.5 16.832031 4.832031 20.167969 C 7.917969 23.25 12.5 24.082031 16.332031 22.582031 L 31.582031 37.832031 C 32.25 38.5 33.332031 38.5 33.917969 37.832031 L 37.832031 33.917969 C 38.5 33.332031 38.5 32.25 37.832031 31.582031 Z M 37.832031 31.582031 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 761 B |
Before Width: | Height: | Size: 224 B |
6
icons/ic_chevron_left_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 25.691406 12.359375 L 23.332031 10 L 13.332031 20 L 23.332031 30 L 25.691406 27.640625 L 18.050781 20 Z M 25.691406 12.359375 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 429 B |
Before Width: | Height: | Size: 225 B |
6
icons/ic_chevron_right_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 16.667969 10 L 14.308594 12.359375 L 21.949219 20 L 14.308594 27.640625 L 16.667969 30 L 26.667969 20 Z M 16.667969 10 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 422 B |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 321 B |
6
icons/ic_computer_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 33.332031 30 C 35.175781 30 36.648438 28.507812 36.648438 26.667969 L 36.667969 10 C 36.667969 8.160156 35.175781 6.667969 33.332031 6.667969 L 6.667969 6.667969 C 4.824219 6.667969 3.332031 8.160156 3.332031 10 L 3.332031 26.667969 C 3.332031 28.507812 4.824219 30 6.667969 30 L 0 30 L 0 33.332031 L 40 33.332031 L 40 30 Z M 6.667969 10 L 33.332031 10 L 33.332031 26.667969 L 6.667969 26.667969 Z M 6.667969 10 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 278 B |
6
icons/ic_delete_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 10 31.667969 C 10 33.507812 11.492188 35 13.332031 35 L 26.667969 35 C 28.507812 35 30 33.507812 30 31.667969 L 30 11.667969 L 10 11.667969 Z M 31.667969 6.667969 L 25.832031 6.667969 L 24.167969 5 L 15.832031 5 L 14.167969 6.667969 L 8.332031 6.667969 L 8.332031 10 L 31.667969 10 Z M 31.667969 6.667969 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 608 B |
Before Width: | Height: | Size: 372 B |
6
icons/ic_sd_storage_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 30 3.332031 L 16.667969 3.332031 L 6.699219 13.332031 L 6.667969 33.332031 C 6.667969 35.167969 8.167969 36.667969 10 36.667969 L 30 36.667969 C 31.832031 36.667969 33.332031 35.167969 33.332031 33.332031 L 33.332031 6.667969 C 33.332031 4.832031 31.832031 3.332031 30 3.332031 Z M 20 13.332031 L 16.667969 13.332031 L 16.667969 6.667969 L 20 6.667969 Z M 25 13.332031 L 21.667969 13.332031 L 21.667969 6.667969 L 25 6.667969 Z M 30 13.332031 L 26.667969 13.332031 L 26.667969 6.667969 L 30 6.667969 Z M 30 13.332031 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 820 B |
Before Width: | Height: | Size: 235 B |
6
icons/ic_storage_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 3.332031 33.332031 L 36.667969 33.332031 L 36.667969 26.667969 L 3.332031 26.667969 Z M 6.667969 28.332031 L 10 28.332031 L 10 31.667969 L 6.667969 31.667969 Z M 3.332031 6.667969 L 3.332031 13.332031 L 36.667969 13.332031 L 36.667969 6.667969 Z M 10 11.667969 L 6.667969 11.667969 L 6.667969 8.332031 L 10 8.332031 Z M 3.332031 23.332031 L 36.667969 23.332031 L 36.667969 16.667969 L 3.332031 16.667969 Z M 6.667969 18.332031 L 10 18.332031 L 10 21.667969 L 6.667969 21.667969 Z M 6.667969 18.332031 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 804 B |
Before Width: | Height: | Size: 513 B |
6
icons/ic_usb_40px.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40pt" height="40pt" viewBox="0 0 40 40" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 25 11.667969 L 25 18.332031 L 26.667969 18.332031 L 26.667969 21.667969 L 21.667969 21.667969 L 21.667969 8.332031 L 25 8.332031 L 20 1.667969 L 15 8.332031 L 18.332031 8.332031 L 18.332031 21.667969 L 13.332031 21.667969 L 13.332031 18.214844 C 14.507812 17.609375 15.332031 16.417969 15.332031 15 C 15.332031 12.976562 13.691406 11.332031 11.667969 11.332031 C 9.640625 11.332031 8 12.976562 8 15 C 8 16.417969 8.824219 17.609375 10 18.214844 L 10 21.667969 C 10 23.507812 11.492188 25 13.332031 25 L 18.332031 25 L 18.332031 30.082031 C 17.148438 30.691406 16.332031 31.910156 16.332031 33.332031 C 16.332031 35.359375 17.976562 37 20 37 C 22.023438 37 23.667969 35.359375 23.667969 33.332031 C 23.667969 31.910156 22.851562 30.691406 21.667969 30.082031 L 21.667969 25 L 26.667969 25 C 28.507812 25 30 23.507812 30 21.667969 L 30 18.332031 L 31.667969 18.332031 L 31.667969 11.667969 Z M 25 11.667969 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/rpi2-hires.png
Normal file
After Width: | Height: | Size: 68 KiB |
|
@ -476,6 +476,7 @@ void ImageWriter::pollNetwork()
|
||||||
if (!a.isLoopback() && a.scopeId().isEmpty())
|
if (!a.isLoopback() && a.scopeId().isEmpty())
|
||||||
{
|
{
|
||||||
/* Not a loopback or IPv6 link-local address, so online */
|
/* Not a loopback or IPv6 link-local address, so online */
|
||||||
|
qDebug() << "IP:" << a;
|
||||||
_online = true;
|
_online = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -484,14 +485,23 @@ void ImageWriter::pollNetwork()
|
||||||
if (_online)
|
if (_online)
|
||||||
{
|
{
|
||||||
_networkchecktimer.stop();
|
_networkchecktimer.stop();
|
||||||
qDebug() << "Network online. Synchronizing time.";
|
|
||||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
// Wait another 0.1 sec, as dhcpcd may not have set up nameservers yet
|
||||||
connect(manager, SIGNAL(finished(QNetworkReply*)), SLOT(onTimeSyncReply(QNetworkReply*)));
|
QTimer::singleShot(100, this, SLOT(syncTime()));
|
||||||
manager->head(QNetworkRequest(QUrl(TIME_URL)));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageWriter::syncTime()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
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)
|
void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
@ -508,7 +518,8 @@ void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: try again later?
|
qDebug() << "Error synchronizing time. Trying again in 3 seconds";
|
||||||
|
QTimer::singleShot(3000, this, SLOT(syncTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
@ -520,6 +531,76 @@ bool ImageWriter::isEmbeddedMode()
|
||||||
return _embeddedMode;
|
return _embeddedMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mount any USB sticks that can contain source images under /media */
|
||||||
|
bool ImageWriter::mountUsbSourceMedia()
|
||||||
|
{
|
||||||
|
int devices = 0;
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QDir dir("/sys/class/block");
|
||||||
|
QStringList list = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
if (!dir.exists("/media"))
|
||||||
|
dir.mkdir("/media");
|
||||||
|
|
||||||
|
for (auto devname : list)
|
||||||
|
{
|
||||||
|
if (!devname.startsWith("mmcblk0") && !QFile::symLinkTarget("/sys/class/block/"+devname).contains("/devices/virtual/"))
|
||||||
|
{
|
||||||
|
QString mntdir = "/media/"+devname;
|
||||||
|
|
||||||
|
if (dir.exists(mntdir))
|
||||||
|
{
|
||||||
|
devices++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.mkdir(mntdir);
|
||||||
|
QStringList args = { "-o", "ro", QString("/dev/")+devname, mntdir };
|
||||||
|
|
||||||
|
if ( QProcess::execute("mount", args) == 0 )
|
||||||
|
devices++;
|
||||||
|
else
|
||||||
|
dir.rmdir(mntdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return devices > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ImageWriter::getUsbSourceOSlist()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QJsonArray oslist;
|
||||||
|
QDir dir("/media");
|
||||||
|
QStringList medialist = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
QStringList namefilters = {"*.img", "*.zip", "*.gz", "*.xz"};
|
||||||
|
|
||||||
|
for (auto devname : medialist)
|
||||||
|
{
|
||||||
|
QDir subdir("/media/"+devname);
|
||||||
|
QStringList files = subdir.entryList(namefilters, QDir::Files, QDir::Name);
|
||||||
|
for (auto file : files)
|
||||||
|
{
|
||||||
|
QString path = "/media/"+devname+"/"+file;
|
||||||
|
QFileInfo fi(path);
|
||||||
|
|
||||||
|
QJsonObject f = {
|
||||||
|
{"name", file},
|
||||||
|
{"description", devname+"/"+file},
|
||||||
|
{"url", QUrl::fromLocalFile(path).toString() },
|
||||||
|
{"release_date", ""},
|
||||||
|
{"image_download_size", fi.size()}
|
||||||
|
};
|
||||||
|
oslist.append(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QJsonDocument(oslist).toJson();
|
||||||
|
#else
|
||||||
|
return QByteArray();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void MountUtilsLog(std::string msg) {
|
void MountUtilsLog(std::string msg) {
|
||||||
qDebug() << "mountutils:" << msg.c_str();
|
qDebug() << "mountutils:" << msg.c_str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,16 @@ public:
|
||||||
/* Returns true if online */
|
/* Returns true if online */
|
||||||
Q_INVOKABLE bool isOnline();
|
Q_INVOKABLE bool isOnline();
|
||||||
|
|
||||||
|
/* Returns true if run on embedded Linux platform */
|
||||||
Q_INVOKABLE bool isEmbeddedMode();
|
Q_INVOKABLE bool isEmbeddedMode();
|
||||||
|
|
||||||
|
/* Mount any USB sticks that can contain source images under /media
|
||||||
|
Returns true if at least one device was mounted */
|
||||||
|
Q_INVOKABLE bool mountUsbSourceMedia();
|
||||||
|
|
||||||
|
/* Returns a json formatted list of the OS images found on USB stick */
|
||||||
|
Q_INVOKABLE QByteArray getUsbSourceOSlist();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/* We are emiting signals with QVariant as parameters because QML likes it that way */
|
/* We are emiting signals with QVariant as parameters because QML likes it that way */
|
||||||
|
|
||||||
|
@ -93,6 +101,7 @@ protected slots:
|
||||||
|
|
||||||
void pollProgress();
|
void pollProgress();
|
||||||
void pollNetwork();
|
void pollNetwork();
|
||||||
|
void syncTime();
|
||||||
void onSuccess();
|
void onSuccess();
|
||||||
void onError(QString msg);
|
void onError(QString msg);
|
||||||
void onFileSelected(QString filename);
|
void onFileSelected(QString filename);
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace Drivelist
|
||||||
std::vector<DeviceDescriptor> deviceList;
|
std::vector<DeviceDescriptor> deviceList;
|
||||||
|
|
||||||
QProcess p;
|
QProcess p;
|
||||||
p.start("lsblk --bytes --json --paths --output-all");
|
QStringList args = { "--bytes", "--json", "--paths", "--output-all" };
|
||||||
|
p.start("lsblk", args);
|
||||||
p.waitForFinished(2000);
|
p.waitForFinished(2000);
|
||||||
QByteArray output = p.readAll();
|
QByteArray output = p.readAll();
|
||||||
|
|
||||||
|
|
10
main.cpp
|
@ -17,6 +17,7 @@
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QScreen>
|
||||||
#ifndef QT_NO_WIDGETS
|
#ifndef QT_NO_WIDGETS
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +38,15 @@ int main(int argc, char *argv[])
|
||||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||||
#endif
|
#endif
|
||||||
#ifdef QT_NO_WIDGETS
|
#ifdef QT_NO_WIDGETS
|
||||||
|
{
|
||||||
|
QGuiApplication tmp(argc, argv);
|
||||||
|
int h = QGuiApplication::primaryScreen()->geometry().height();
|
||||||
|
if (h > 720)
|
||||||
|
{
|
||||||
|
qputenv("QT_SCALE_FACTOR", QByteArray::number(h / 720.0, 'f', 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
#else
|
#else
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
65
main.qml
|
@ -13,12 +13,13 @@ import Qt.labs.settings 1.0
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: window
|
id: window
|
||||||
visible: true
|
visible: true
|
||||||
width: 680
|
|
||||||
height: 420
|
width: imageWriter.isEmbeddedMode() ? -1 : 680
|
||||||
minimumWidth: 680
|
height: imageWriter.isEmbeddedMode() ? -1 : 420
|
||||||
maximumWidth: 680
|
minimumWidth: imageWriter.isEmbeddedMode() ? -1 : 680
|
||||||
minimumHeight: 420
|
maximumWidth: imageWriter.isEmbeddedMode() ? -1 : 680
|
||||||
maximumHeight: 420
|
minimumHeight: imageWriter.isEmbeddedMode() ? -1 : 420
|
||||||
|
maximumHeight: imageWriter.isEmbeddedMode() ? -1 : 420
|
||||||
|
|
||||||
title: qsTr("Raspberry Pi Imager v%1").arg(imageWriter.constantVersion())
|
title: qsTr("Raspberry Pi Imager v%1").arg(imageWriter.constantVersion())
|
||||||
|
|
||||||
|
@ -50,13 +51,18 @@ ApplicationWindow {
|
||||||
id: bg
|
id: bg
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Image {
|
Rectangle {
|
||||||
id: image
|
implicitHeight: window.height/2
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Image {
|
||||||
Layout.preferredWidth: window.width
|
id: image
|
||||||
fillMode: Image.PreserveAspectFit
|
Layout.fillWidth: true
|
||||||
source: "icons/rpi2.png"
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: imageWriter.isEmbeddedMode() ? "icons/rpi2-hires.png" : "icons/rpi2.png"
|
||||||
|
width: window.width
|
||||||
|
height: window.height/2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -347,7 +353,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
ListElement {
|
ListElement {
|
||||||
url: "internal://format"
|
url: "internal://format"
|
||||||
icon: "icons/ic_delete_40px.png"
|
icon: "icons/ic_delete_40px.svg"
|
||||||
extract_size: 0
|
extract_size: 0
|
||||||
image_download_size: 0
|
image_download_size: 0
|
||||||
extract_sha256: ""
|
extract_sha256: ""
|
||||||
|
@ -362,7 +368,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
ListElement {
|
ListElement {
|
||||||
url: ""
|
url: ""
|
||||||
icon: "icons/ic_computer_40px.png"
|
icon: "icons/ic_computer_40px.svg"
|
||||||
name: qsTr("Use custom")
|
name: qsTr("Use custom")
|
||||||
description: qsTr("Select a custom .img from your computer")
|
description: qsTr("Select a custom .img from your computer")
|
||||||
}
|
}
|
||||||
|
@ -379,7 +385,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
ListElement {
|
ListElement {
|
||||||
url: ""
|
url: ""
|
||||||
icon: "icons/ic_chevron_left_40px.png"
|
icon: "icons/ic_chevron_left_40px.svg"
|
||||||
extract_size: 0
|
extract_size: 0
|
||||||
image_download_size: 0
|
image_download_size: 0
|
||||||
extract_sha256: ""
|
extract_sha256: ""
|
||||||
|
@ -421,7 +427,7 @@ ApplicationWindow {
|
||||||
width: 64
|
width: 64
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
source: icon == "icons/ic_build_48px.svg" ? "icons/ic_build_40px.png": icon
|
source: icon == "icons/ic_build_48px.svg" ? "icons/ic_build_40px.svg": icon
|
||||||
verticalAlignment: Image.AlignVCenter
|
verticalAlignment: Image.AlignVCenter
|
||||||
height: parent.parent.parent.height
|
height: parent.parent.parent.height
|
||||||
fillMode: Image.Pad
|
fillMode: Image.Pad
|
||||||
|
@ -447,6 +453,8 @@ ApplicationWindow {
|
||||||
if (typeof(url) == "string" && url != "" && url != "internal://format") {
|
if (typeof(url) == "string" && url != "" && url != "internal://format") {
|
||||||
if (typeof(extract_sha256) != "undefined" && imageWriter.isCached(url,extract_sha256)) {
|
if (typeof(extract_sha256) != "undefined" && imageWriter.isCached(url,extract_sha256)) {
|
||||||
txt += "<br>"+qsTr("Cached on your computer")
|
txt += "<br>"+qsTr("Cached on your computer")
|
||||||
|
} else if (url.startsWith("file://")) {
|
||||||
|
txt += "<br>"+qsTr("Local file")
|
||||||
} else {
|
} else {
|
||||||
txt += "<br>"+qsTr("Online - %1 GB download").arg((image_download_size/1073741824).toFixed(1));
|
txt += "<br>"+qsTr("Online - %1 GB download").arg((image_download_size/1073741824).toFixed(1));
|
||||||
}
|
}
|
||||||
|
@ -467,7 +475,7 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
Image {
|
Image {
|
||||||
source: "icons/ic_chevron_right_40px.png"
|
source: "icons/ic_chevron_right_40px.svg"
|
||||||
visible: (typeof(subitems) == "object" && subitems.count) || (typeof(subitems_url) == "string" && subitems_url != "" && subitems_url != "internal://back")
|
visible: (typeof(subitems) == "object" && subitems.count) || (typeof(subitems_url) == "string" && subitems_url != "" && subitems_url != "internal://back")
|
||||||
height: parent.parent.parent.height
|
height: parent.parent.parent.height
|
||||||
fillMode: Image.Pad
|
fillMode: Image.Pad
|
||||||
|
@ -531,8 +539,22 @@ ApplicationWindow {
|
||||||
imageWriter.openFileDialog()
|
imageWriter.openFileDialog()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// FIXME: provide QML file dialog
|
if (imageWriter.mountUsbSourceMedia()) {
|
||||||
onError("Using custom images is not implemented on this platform yet.")
|
if (subosmodel.count>1)
|
||||||
|
{
|
||||||
|
subosmodel.remove(1, subosmodel.count-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var oslist = JSON.parse(imageWriter.getUsbSourceOSlist())
|
||||||
|
for (var i in oslist) {
|
||||||
|
subosmodel.append(oslist[i])
|
||||||
|
}
|
||||||
|
osswipeview.setCurrentIndex(1)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onError(qsTr("Connect an USB stick containing images first.<br>The images must be located in the root folder of the USB stick."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
imageWriter.setSrc(url, image_download_size, extract_size, typeof(extract_sha256) != "undefined" ? extract_sha256 : "", typeof(contains_multiple_files) != "undefined" ? contains_multiple_files : false)
|
imageWriter.setSrc(url, image_download_size, extract_size, typeof(extract_sha256) != "undefined" ? extract_sha256 : "", typeof(contains_multiple_files) != "undefined" ? contains_multiple_files : false)
|
||||||
|
@ -547,7 +569,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Popup for SD card device selection
|
Popup for SD card device selection
|
||||||
*/
|
*/
|
||||||
|
@ -658,7 +679,7 @@ ApplicationWindow {
|
||||||
width: 64
|
width: 64
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
source: isUsb ? "icons/ic_usb_40px.png" : isScsi ? "icons/ic_storage_40px.png" : "icons/ic_sd_storage_40px.png"
|
source: isUsb ? "icons/ic_usb_40px.svg" : isScsi ? "icons/ic_storage_40px.svg" : "icons/ic_sd_storage_40px.svg"
|
||||||
verticalAlignment: Image.AlignVCenter
|
verticalAlignment: Image.AlignVCenter
|
||||||
height: parent.parent.parent.height
|
height: parent.parent.parent.height
|
||||||
fillMode: Image.Pad
|
fillMode: Image.Pad
|
||||||
|
|
18
qml.qrc
|
@ -7,14 +7,14 @@
|
||||||
<file>fonts/Roboto-Bold.ttf</file>
|
<file>fonts/Roboto-Bold.ttf</file>
|
||||||
<file>fonts/Roboto-Light.ttf</file>
|
<file>fonts/Roboto-Light.ttf</file>
|
||||||
<file>fonts/Roboto-Regular.ttf</file>
|
<file>fonts/Roboto-Regular.ttf</file>
|
||||||
<file>icons/ic_chevron_right_40px.png</file>
|
<file>icons/rpi2-hires.png</file>
|
||||||
<file>icons/ic_chevron_left_40px.png</file>
|
<file>icons/ic_build_40px.svg</file>
|
||||||
<file>icons/ic_computer_40px.png</file>
|
<file>icons/ic_chevron_left_40px.svg</file>
|
||||||
<file>icons/ic_delete_40px.png</file>
|
<file>icons/ic_chevron_right_40px.svg</file>
|
||||||
<file>icons/ic_usb_40px.png</file>
|
<file>icons/ic_computer_40px.svg</file>
|
||||||
<file>icons/ic_storage_40px.png</file>
|
<file>icons/ic_delete_40px.svg</file>
|
||||||
<file>icons/ic_sd_storage_40px.png</file>
|
<file>icons/ic_sd_storage_40px.svg</file>
|
||||||
<file>icons/ic_build_40px.png</file>
|
<file>icons/ic_storage_40px.svg</file>
|
||||||
<file>icons/ic_close_18px.png</file>
|
<file>icons/ic_usb_40px.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|