mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 16:24:57 +00:00

Most of the models were just calling did_update anyway, which is pointless since it can be unified to the base Model class. Instead, code calling update() will now call invalidate(), which functions identically and is more obvious in what it does. Additionally, a default implementation is provided, which removes the need to add empty implementations of update() for each model subclass. Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
144 lines
3.8 KiB
C++
144 lines
3.8 KiB
C++
/*
|
|
* Copyright (c) 2021, Nick Vella <nick@nxk.io>
|
|
* Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "ProjectTemplatesModel.h"
|
|
|
|
#include <AK/LexicalPath.h>
|
|
#include <AK/QuickSort.h>
|
|
#include <LibCore/DirIterator.h>
|
|
#include <LibGUI/Variant.h>
|
|
#include <LibGfx/TextAlignment.h>
|
|
#include <stdio.h>
|
|
|
|
namespace HackStudio {
|
|
|
|
ProjectTemplatesModel::ProjectTemplatesModel()
|
|
: m_templates()
|
|
, m_mapping()
|
|
{
|
|
auto watcher_or_error = Core::FileWatcher::create();
|
|
if (!watcher_or_error.is_error()) {
|
|
m_file_watcher = watcher_or_error.release_value();
|
|
m_file_watcher->on_change = [&](auto) {
|
|
invalidate();
|
|
};
|
|
|
|
auto watch_result = m_file_watcher->add_watch(
|
|
ProjectTemplate::templates_path(),
|
|
Core::FileWatcherEvent::Type::ChildCreated
|
|
| Core::FileWatcherEvent::Type::ChildDeleted);
|
|
|
|
if (watch_result.is_error()) {
|
|
warnln("Unable to watch templates directory, templates will not automatically refresh. Error: {}", watch_result.error());
|
|
}
|
|
} else {
|
|
warnln("Unable to watch templates directory, templates will not automatically refresh. Error: {}", watcher_or_error.error());
|
|
}
|
|
|
|
rescan_templates();
|
|
}
|
|
|
|
ProjectTemplatesModel::~ProjectTemplatesModel()
|
|
{
|
|
}
|
|
|
|
int ProjectTemplatesModel::row_count(const GUI::ModelIndex&) const
|
|
{
|
|
return m_mapping.size();
|
|
}
|
|
|
|
int ProjectTemplatesModel::column_count(const GUI::ModelIndex&) const
|
|
{
|
|
return Column::__Count;
|
|
}
|
|
|
|
String ProjectTemplatesModel::column_name(int column) const
|
|
{
|
|
switch (column) {
|
|
case Column::Icon:
|
|
return "Icon";
|
|
case Column::Id:
|
|
return "ID";
|
|
case Column::Name:
|
|
return "Name";
|
|
}
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
GUI::Variant ProjectTemplatesModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
|
|
{
|
|
if (static_cast<size_t>(index.row()) >= m_mapping.size())
|
|
return {};
|
|
|
|
if (role == GUI::ModelRole::TextAlignment)
|
|
return Gfx::TextAlignment::CenterLeft;
|
|
|
|
if (role == GUI::ModelRole::Display) {
|
|
switch (index.column()) {
|
|
case Column::Name:
|
|
return m_mapping[index.row()]->name();
|
|
case Column::Id:
|
|
return m_mapping[index.row()]->id();
|
|
}
|
|
}
|
|
|
|
if (role == GUI::ModelRole::Icon) {
|
|
return m_mapping[index.row()]->icon();
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
RefPtr<ProjectTemplate> ProjectTemplatesModel::template_for_index(const GUI::ModelIndex& index)
|
|
{
|
|
if (static_cast<size_t>(index.row()) >= m_mapping.size())
|
|
return {};
|
|
|
|
return m_mapping[index.row()];
|
|
}
|
|
|
|
void ProjectTemplatesModel::update()
|
|
{
|
|
rescan_templates();
|
|
did_update();
|
|
}
|
|
|
|
void ProjectTemplatesModel::rescan_templates()
|
|
{
|
|
m_templates.clear();
|
|
|
|
// Iterate over template manifest INI files in the templates path
|
|
Core::DirIterator di(ProjectTemplate::templates_path(), Core::DirIterator::SkipDots);
|
|
if (di.has_error()) {
|
|
warnln("DirIterator: {}", di.error_string());
|
|
return;
|
|
}
|
|
|
|
while (di.has_next()) {
|
|
auto full_path = LexicalPath(di.next_full_path());
|
|
if (!full_path.has_extension(".ini"))
|
|
continue;
|
|
|
|
auto project_template = ProjectTemplate::load_from_manifest(full_path.string());
|
|
if (!project_template) {
|
|
warnln("Template manifest {} is invalid.", full_path.string());
|
|
continue;
|
|
}
|
|
|
|
m_templates.append(project_template.release_nonnull());
|
|
}
|
|
|
|
// Enumerate the loaded projects into a sorted mapping, by priority value descending.
|
|
m_mapping.clear();
|
|
for (auto& project_template : m_templates)
|
|
m_mapping.append(&project_template);
|
|
quick_sort(m_mapping, [](auto a, auto b) {
|
|
return a->priority() > b->priority();
|
|
});
|
|
}
|
|
|
|
}
|