// SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 flowln * Copyright (C) 2022 Sefa Eyeoglu * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2013-2021 MultiMC Contributors * * 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. */ #include "ModFolderModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "Application.h" #include "Json.h" #include "minecraft/mod/tasks/LocalModParseTask.h" #include "minecraft/mod/tasks/LocalResourceUpdateTask.h" #include "modplatform/ModIndex.h" #include "modplatform/flame/FlameAPI.h" #include "modplatform/flame/FlameModIndex.h" ModFolderModel::ModFolderModel(const QDir& dir, BaseInstance* instance, bool is_indexed, bool create_dir, QObject* parent) : ResourceFolderModel(QDir(dir), instance, is_indexed, create_dir, parent) { m_column_names = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider", "Size", "Side", "Loaders", "Minecraft Versions", "Release Type" }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("Side"), tr("Loaders"), tr("Minecraft Versions"), tr("Release Type") }); m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER, SortType::SIZE, SortType::SIDE, SortType::LOADERS, SortType::MC_VERSIONS, SortType::RELEASE_TYPE }; m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; m_columnsHideable = { false, true, false, true, true, true, true, true, true, true, true }; m_columnsHiddenByDefault = { false, false, false, false, false, false, false, true, true, true, true }; } QVariant ModFolderModel::data(const QModelIndex& index, int role) const { if (!validateIndex(index)) return {}; int row = index.row(); int column = index.column(); switch (role) { case Qt::DisplayRole: switch (column) { case NameColumn: return m_resources[row]->name(); case VersionColumn: { switch (at(row).type()) { case ResourceType::FOLDER: return tr("Folder"); case ResourceType::SINGLEFILE: return tr("File"); default: break; } return at(row).version(); } case DateColumn: return at(row).dateTimeChanged(); case ProviderColumn: { return at(row).provider(); } case SideColumn: { return at(row).side(); } case LoadersColumn: { return at(row).loaders(); } case McVersionsColumn: { return at(row).mcVersions(); } case ReleaseTypeColumn: { return at(row).releaseType(); } case SizeColumn: return at(row).sizeStr(); default: return QVariant(); } case Qt::ToolTipRole: if (column == NameColumn) { if (at(row).isSymLinkUnder(instDirPath())) { return m_resources[row]->internal_id() + tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." "\nCanonical Path: %1") .arg(at(row).fileinfo().canonicalFilePath()); } if (at(row).isMoreThanOneHardLink()) { return m_resources[row]->internal_id() + tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); } } return m_resources[row]->internal_id(); case Qt::DecorationRole: { if (column == NameColumn && (at(row).isSymLinkUnder(instDirPath()) || at(row).isMoreThanOneHardLink())) return APPLICATION->getThemedIcon("status-yellow"); if (column == ImageColumn) { return at(row).icon({ 32, 32 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding); } return {}; } case Qt::SizeHintRole: if (column == ImageColumn) { return QSize(32, 32); } return {}; case Qt::CheckStateRole: switch (column) { case ActiveColumn: return at(row).enabled() ? Qt::Checked : Qt::Unchecked; default: return QVariant(); } default: return QVariant(); } } QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientation orientation, int role) const { switch (role) { case Qt::DisplayRole: switch (section) { case ActiveColumn: case NameColumn: case VersionColumn: case DateColumn: case ProviderColumn: case ImageColumn: case SideColumn: case LoadersColumn: case McVersionsColumn: case ReleaseTypeColumn: case SizeColumn: return columnNames().at(section); default: return QVariant(); } case Qt::ToolTipRole: switch (section) { case ActiveColumn: return tr("Is the mod enabled?"); case NameColumn: return tr("The name of the mod."); case VersionColumn: return tr("The version of the mod."); case DateColumn: return tr("The date and time this mod was last changed (or added)."); case ProviderColumn: return tr("The source provider of the mod."); case SideColumn: return tr("On what environment the mod is running."); case LoadersColumn: return tr("The mod loader."); case McVersionsColumn: return tr("The supported minecraft versions."); case ReleaseTypeColumn: return tr("The release type."); case SizeColumn: return tr("The size of the mod."); default: return QVariant(); } default: return QVariant(); } return QVariant(); } int ModFolderModel::columnCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : NUM_COLUMNS; } Task* ModFolderModel::createParseTask(Resource& resource) { return new LocalModParseTask(m_next_resolution_ticket, resource.type(), resource.fileinfo()); } bool ModFolderModel::isValid() { return m_dir.exists() && m_dir.isReadable(); } void ModFolderModel::onParseSucceeded(int ticket, QString mod_id) { auto iter = m_active_parse_tasks.constFind(ticket); if (iter == m_active_parse_tasks.constEnd()) return; int row = m_resources_index[mod_id]; auto parse_task = *iter; auto cast_task = static_cast(parse_task.get()); Q_ASSERT(cast_task->token() == ticket); auto resource = find(mod_id); auto result = cast_task->result(); if (result && resource) resource->finishResolvingWithDetails(std::move(result->details)); emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1)); }