Files
minecraft-launcher/doc/qml/SeasonalBuildsDialog.md
2026-09-03 09:16:56 +03:00

11 KiB
Raw Permalink Blame History

SeasonalBuildsDialog

Обзор компонента

Minecraft_launcher — десктопный лаунчер Minecraft на Qt Quick. Кроме сборок, которые пользователь собирает сам, он умеет ставить готовые сезонные сборки с сервера лаунчера: набор модов под конкретную версию игры и модлоадер, подготовленный заранее и выдаваемый целиком.

SeasonalBuildsDialog — окно этого каталога: таблица со всем, что нужно знать, чтобы решить, ставить сборку или нет, и одна кнопка, которая делает всё остальное — заводит сборку, ставит версию игры, модлоадер, Java и раскладывает файлы. Окно также показывает, что установленная сборка устарела, и предлагает обновить её до свежей ревизии.

Таблица собрана из строк Row с фиксированными колонками, а не из TableView: в проекте нет ни одной модели QAbstractItemModel, а строки приходят готовыми QVariantMap — заводить ради семи колонок отдельную модель незачем.

Место в проекте и зависимости

В начале файла объявлена pragma ComponentBehavior: Bound. Импортирует QtQuick и QtQuick.Controls 2.15 — слои QtQuick.Layouts здесь не нужны, вся раскладка на якорях и фиксированных ширинах колонок.

Работает с C++-типом LauncherBackend (launcherbackend.h, QML_ELEMENT в модуле Minecraft_launcher), передаваемым снаружи в свойство backend. Читает свойства seasonalCatalog, seasonalCatalogLoading, seasonalCatalogError, seasonalInstalling и busy, вызывает refreshSeasonalCatalog() и installSeasonalBuild().

Объявлен в QML_FILES модуля (CMakeLists.txt). Инстанцируется в Main.

Строки каталога приходят из C++ уже отсортированными и сведёнными с локальными записями — окно показывает статус, не считая ничего само. Запись содержит поля id, name, description, minecraftVersion, loaderTitle, loaderVersion, modCount, seasonStart, seasonEnd, status, revision, installedRevision, updateAvailable, sizeBytes и serverUrl.

Иерархия и роль

Корневой тип — Dialog: модальный, 960×560 px, нулевой внутренний отступ, тёмный фон со скруглением и акцентной рамкой.

Политика закрытия зависит от состояния: пока идёт установка, окно закрывается только кнопкой (Popup.NoAutoClose), потому что случайный щелчок мимо не должен спрятать единственную видимую отмену; в остальное время работают Escape и щелчок мимо.

Содержимое — шапка таблицы (Row с Repeater по columns), разделительная линия, список строк и сообщение по центру для пустого состояния. Строка списка — Rectangle высотой 36 px с вложенным Row, который повторяет тот же набор колонок; ширины берутся из общего описания columns, поэтому шапка и строки не могут разъехаться.

Подвал высотой 76 px несёт описание и размер выбранной сборки (они длинные и в таблицу не помещаются, а решение принимается именно по ним) и две кнопки — обновления списка и установки.

Свойства

Свойство Тип По умолчанию Обязательное Описание
backend var Да Экземпляр LauncherBackend — источник каталога сезонных сборок и исполнитель установки.
selectedId string "" Нет Идентификатор выбранной строки. Хранится по id, а не по индексу: список обновляется под руками, и индекс после обновления указывал бы на другую сборку.
columns var (только чтение) список из семи колонок Нет Описание таблицы: массив объектов с полями key (поле записи), title (заголовок), width (ширина в пикселях) и align (выравнивание). Колонки: название, версия, загрузчик, число модов, начало и конец сезона, статус. Ширины собраны в одном месте, потому что их повторяют и шапка, и делегат строки.
entries var (только чтение) backend.seasonalCatalog Нет Строки каталога напрямую из бэкенда. Отбора и сортировки в окне нет.
selectedEntry var (только чтение) вычисляется Нет Полная запись выбранной сборки или null, если ничего не выбрано. От неё зависят подвал и доступность кнопки установки.

Сигналы

Собственных сигналов компонент не объявляет. Результат работы окна виден через состояние бэкенда: установка меняет список сборок и запускает загрузку, за ходом которой следит главное окно.

Методы

openCatalog() : void

Открывает окно. Обновление каталога происходит само в обработчике onAboutToShow, который просит у бэкенда refreshSeasonalCatalog(false) — без принудительного обхода кэша: свежий кэш отвечает без сети, поэтому вызов при каждом открытии ничего не стоит.

formatMb(bytes) : string

Переводит размер в байтах в строку с мегабайтами и одним знаком после запятой. Для нулевого или отсутствующего значения возвращает пустую строку, чтобы размер просто не попал в строку подвала.

cellText(entry, string key) : string

Возвращает текст ячейки для записи и ключа колонки. Для всех колонок это значение одноимённого поля записи, приведённое к строке; исключение — колонка загрузчика, где название и версия склеиваются в одну подпись, а при пустой версии остаётся только название.

installSelected() : void

Ставит выбранную сборку. Ничего не делает, если строка не выбрана или лаунчер занят другой операцией: установка занимает и панель загрузки, и .minecraft целиком, поэтому вторую начинать нельзя. Иначе вызывает installSeasonalBuild() у бэкенда.

Вызывается кнопкой установки и двойным щелчком по строке.

Взаимодействие с другими компонентами

Со стороны родителя. Main задаёт backend и открывает окно вызовом openCatalog(). Обратной связи наружу через сигналы нет.

Со стороны бэкенда. Всё содержимое таблицы — привязка к seasonalCatalog, поэтому обновление каталога и изменение статуса установленной сборки перерисовывают окно сами. Пустое состояние различает три случая по seasonalCatalogLoading и seasonalCatalogError: идёт загрузка, сборок пока нет, произошла ошибка — её текст показывается прямо на месте строк, потому что пустой список и ошибка выглядят одинаково пустыми.

Занятость. Кнопка установки выключается по общему признаку busy, кнопка обновления списка — по seasonalCatalogLoading (её подпись при этом меняется на «Обновление…»). Политика закрытия окна завязана на seasonalInstalling.

Обновление ревизии. Если у записи выставлен updateAvailable, статус в таблице подсвечивается акцентным цветом, в подвале дописывается установленная ревизия, а кнопка установки называется «Обновить». Отдельного пути обновления нет — это тот же вызов installSeasonalBuild().

Ход установки. Окно не показывает прогресс: за это отвечает плашка ProgressPanel в главном окне, а отмена — метод cancelSeasonalInstall() бэкенда.

Пример использования

SeasonalBuildsDialog {
    id: seasonalDialog
    parent: Overlay.overlay
    backend: launcherBackend
}

Button {
    text: qsTr("Сезонные сборки")
    onClicked: seasonalDialog.openCatalog()
}

При создании этого документа использовался ИИ.