11 KiB
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()
}
При создании этого документа использовался ИИ.