From f0b936a2184be5a6e6d3799a0b35cf26bafe320f Mon Sep 17 00:00:00 2001 From: blocksmith314 Date: Sun, 8 Nov 2026 10:18:41 +0800 Subject: [PATCH] feat(ui): show version, commit and OS in --version and About - CMake generates version.h from the project version and git metadata (commit hash and commit date), falling back to "unknown" outside git - --version prints version, commit, commit date, Qt version and OS before QApplication starts - Help menu contains an About action; Qt moves it to the application menu on macOS (AboutRole), which is the native location - add an app_version CTest case and a HasHelpMenu GUI test --- CMakeLists.txt | 30 +++++++++++++++++++++++++++++- core/version.h.in | 5 +++++ main.cpp | 13 +++++++++++++ mainwindow.cpp | 15 +++++++++++++++ mainwindow.h | 1 + test/test_gui.cpp | 12 ++++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 core/version.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 230a1b2..f03607b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(DigitalImageAnalyzer VERSION 0.1.1 LANGUAGES CXX) +project(DigitalImageAnalyzer VERSION 0.1.2 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -11,6 +11,29 @@ find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Test) qt_standard_project_setup() +# Version metadata for --version and the About dialog. Falls back to +# "unknown" when the sources are built outside a git checkout. +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE DIA_GIT_COMMIT + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) +execute_process( + COMMAND git log -1 --format=%cs + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE DIA_GIT_COMMIT_DATE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) +if(NOT DIA_GIT_COMMIT) + set(DIA_GIT_COMMIT "unknown") +endif() +if(NOT DIA_GIT_COMMIT_DATE) + set(DIA_GIT_COMMIT_DATE "unknown") +endif() +configure_file(core/version.h.in ${CMAKE_BINARY_DIR}/generated/version.h @ONLY) +include_directories(${CMAKE_BINARY_DIR}/generated) + find_package(PkgConfig REQUIRED) pkg_check_modules(AVFORMAT REQUIRED IMPORTED_TARGET libavformat) pkg_check_modules(AVCODEC REQUIRED IMPORTED_TARGET libavcodec) @@ -295,4 +318,9 @@ if (BUILD_TEST) gtest_discover_tests(test_gui PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen") add_dependencies(all_tests test_gui) + + add_test(NAME app_version + COMMAND $ --version) + set_tests_properties(app_version PROPERTIES + PASS_REGULAR_EXPRESSION "Digital Image Analyzer ${PROJECT_VERSION}") endif () diff --git a/core/version.h.in b/core/version.h.in new file mode 100644 index 0000000..b5c5f9b --- /dev/null +++ b/core/version.h.in @@ -0,0 +1,5 @@ +#pragma once + +#define DIA_VERSION "@PROJECT_VERSION@" +#define DIA_GIT_COMMIT "@DIA_GIT_COMMIT@" +#define DIA_GIT_COMMIT_DATE "@DIA_GIT_COMMIT_DATE@" diff --git a/main.cpp b/main.cpp index c3e3e10..8726952 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,21 @@ #include +#include +#include +#include #include "mainwindow.h" +#include "version.h" int main(int argc, char* argv[]) { + for (int i = 1; i < argc; i++) { + if (std::strcmp(argv[i], "--version") == 0) { + std::printf("Digital Image Analyzer %s\ncommit %s (%s)\nQt %s, %s\n", + DIA_VERSION, DIA_GIT_COMMIT, DIA_GIT_COMMIT_DATE, qVersion(), + QSysInfo::prettyProductName().toUtf8().constData()); + return 0; + } + } + QApplication a(argc, argv); MainWindow w; diff --git a/mainwindow.cpp b/mainwindow.cpp index d107374..a1560f7 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include "annexb.h" #include "audio.h" #include "nallistmodel.h" +#include "version.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), parser_(CodecType::kH264) { @@ -266,6 +268,10 @@ void MainWindow::SetupUi() { connect(bottomSplit, &QSplitter::splitterMoved, this, [this](int, int) { SyncSplitterWidths(false); }); + QMenu* helpMenu = menuBar()->addMenu("Help"); + QAction* aboutAct = helpMenu->addAction("About Digital Image Analyzer"); + connect(aboutAct, &QAction::triggered, this, &MainWindow::ShowAbout); + setCentralWidget(mainSplit); top_split_ = topSplit; bottom_split_ = bottomSplit; @@ -293,6 +299,15 @@ void MainWindow::OpenFile() { } } +void MainWindow::ShowAbout() { + QMessageBox::about(this, "About Digital Image Analyzer", + QString("

Digital Image Analyzer %1

" + "

H.264/H.265 bitstream analyzer.

" + "

Commit: %2 (%3)
Qt: %4
OS: %5

") + .arg(DIA_VERSION, DIA_GIT_COMMIT, DIA_GIT_COMMIT_DATE, + qVersion(), QSysInfo::prettyProductName())); +} + void MainWindow::dragEnterEvent(QDragEnterEvent* event) { const QList urls = event->mimeData()->urls(); for (const QUrl& url : urls) { diff --git a/mainwindow.h b/mainwindow.h index 88dd4e6..365266e 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -52,6 +52,7 @@ class MainWindow : public QMainWindow { void ToggleFullscreen(); void OnPlayerTick(); void OnSpeedChanged(int index); + void ShowAbout(); private: static constexpr int MAX_RECENT_FILES = 10; diff --git a/test/test_gui.cpp b/test/test_gui.cpp index a4dceec..f980a8d 100644 --- a/test/test_gui.cpp +++ b/test/test_gui.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -181,6 +182,17 @@ TEST(MainWindowTest, LoadsFileAndUpdatesViews) { EXPECT_TRUE(status_has_nal_count); } +TEST(MainWindowTest, HasHelpMenu) { + MainWindow window; + bool has_help = false; + for (QAction* action : window.menuBar()->actions()) { + if (action->text().contains("Help")) { + has_help = true; + } + } + EXPECT_TRUE(has_help); +} + TEST(MainWindowTest, OpensFileByDrop) { if (!exists(data_path("output.h264"))) { GTEST_SKIP() << "H.264 fixture missing";