Fix missing filewatcher paths

This commit is contained in:
GriffinR
2025-05-01 15:41:37 -04:00
parent 3876b63836
commit f8f6fe827d
5 changed files with 92 additions and 61 deletions

View File

@@ -43,9 +43,13 @@ class ParseUtil
{
public:
ParseUtil();
void setRoot(const QString &dir) { this->root = dir; }
void setUpdatesSplashScreen(bool updates) { this->updatesSplashScreen = updates; }
static QString readTextFile(const QString &path, QString *error = nullptr);
QString loadTextFile(const QString &path, QString *error = nullptr);
bool cacheFile(const QString &path, QString *error = nullptr);
void clearFileCache() { this->fileCache.clear(); }
static int textFileLineCount(const QString &path);
@@ -127,7 +131,6 @@ private:
QHash<QString, int> evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
bool defineNameMatchesFilter(const QString &name, const QSet<QString> &filterList) const;
bool defineNameMatchesFilter(const QString &name, const QSet<QRegularExpression> &filterList) const;
QString loadTextFile(const QString &path, QString *error = nullptr);
QString pathWithRoot(const QString &path);
static const QRegularExpression re_incScriptLabel;

View File

@@ -67,9 +67,9 @@ public:
bool saveTilesImage();
bool savePalettes();
bool appendToHeaders(QString root, QString friendlyName, bool usingAsm);
bool appendToGraphics(QString root, QString friendlyName, bool usingAsm);
bool appendToMetatiles(QString root, QString friendlyName, bool usingAsm);
bool appendToHeaders(const QString &filepath, const QString &friendlyName, bool usingAsm);
bool appendToGraphics(const QString &filepath, const QString &friendlyName, bool usingAsm);
bool appendToMetatiles(const QString &filepath, const QString &friendlyName, bool usingAsm);
void setTilesImage(const QImage &image);

View File

@@ -308,7 +308,10 @@ private:
void setNewLayoutBlockdata(Layout *layout);
void setNewLayoutBorder(Layout *layout);
void ignoreWatchedFileTemporarily(QString filepath);
void watchFile(const QString &filename);
void watchFiles(const QStringList &filenames);
void ignoreWatchedFileTemporarily(const QString &filepath);
void ignoreWatchedFilesTemporarily(const QStringList &filepaths);
void recordFileChange(const QString &filepath);
void resetFileCache();

View File

@@ -249,12 +249,10 @@ QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset
return paletteTable;
}
bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm) {
QString headersFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm)
: projectConfig.getFilePath(ProjectFilePath::tilesets_headers));
QFile file(headersFile);
bool Tileset::appendToHeaders(const QString &filepath, const QString &friendlyName, bool usingAsm) {
QFile file(filepath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
logError(QString("Could not write to file \"%1\"").arg(headersFile));
logError(QString("Could not write to file \"%1\"").arg(filepath));
return false;
}
QString isSecondaryStr = this->is_secondary ? "TRUE" : "FALSE";
@@ -294,12 +292,10 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm)
return true;
}
bool Tileset::appendToGraphics(QString root, QString friendlyName, bool usingAsm) {
QString graphicsFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_graphics_asm)
: projectConfig.getFilePath(ProjectFilePath::tilesets_graphics));
QFile file(graphicsFile);
bool Tileset::appendToGraphics(const QString &filepath, const QString &friendlyName, bool usingAsm) {
QFile file(filepath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
logError(QString("Could not write to file \"%1\"").arg(graphicsFile));
logError(QString("Could not write to file \"%1\"").arg(filepath));
return false;
}
@@ -332,12 +328,10 @@ bool Tileset::appendToGraphics(QString root, QString friendlyName, bool usingAsm
return true;
}
bool Tileset::appendToMetatiles(QString root, QString friendlyName, bool usingAsm) {
QString metatileFile = root + "/" + (usingAsm ? projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles_asm)
: projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles));
QFile file(metatileFile);
bool Tileset::appendToMetatiles(const QString &filepath, const QString &friendlyName, bool usingAsm) {
QFile file(filepath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Append)) {
logError(QString("Could not write to file \"%1\"").arg(metatileFile));
logError(QString("Could not write to file \"%1\"").arg(filepath));
return false;
}

View File

@@ -138,7 +138,9 @@ void Project::resetFileCache() {
projectConfig.getFilePath(ProjectFilePath::global_fieldmap),
};
for (const auto &path : filepaths) {
this->parser.cacheFile(path);
if (this->parser.cacheFile(path)) {
watchFile(path);
}
}
}
@@ -218,6 +220,7 @@ QSet<QString> Project::getTopLevelMapFields() const {
bool Project::readMapJson(const QString &mapName, QJsonDocument * out) {
const QString mapFilepath = QString("%1%2/map.json").arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)).arg(mapName);
watchFile(mapFilepath);
QString error;
if (!parser.tryParseJsonFile(out, mapFilepath, &error)) {
logError(QString("Failed to read map data from '%1': %2").arg(mapFilepath).arg(error));
@@ -488,7 +491,7 @@ bool Project::readMapLayouts() {
clearMapLayouts();
const QString layoutsFilepath = projectConfig.getFilePath(ProjectFilePath::json_layouts);
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(layoutsFilepath));
watchFile(layoutsFilepath);
QJsonDocument layoutsDoc;
QString error;
if (!parser.tryParseJsonFile(&layoutsDoc, layoutsFilepath, &error)) {
@@ -642,11 +645,26 @@ bool Project::saveMapLayouts() {
return true;
}
void Project::ignoreWatchedFileTemporarily(QString filepath) {
void Project::watchFile(const QString &filename) {
this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename));
}
void Project::watchFiles(const QStringList &filenames) {
for (const auto &filename : filenames)
watchFile(filename);
}
void Project::ignoreWatchedFileTemporarily(const QString &filepath) {
// Ignore any file-change events for this filepath for the next 5 seconds.
this->modifiedFileTimestamps.insert(filepath, QDateTime::currentMSecsSinceEpoch() + 5000);
}
void Project::ignoreWatchedFilesTemporarily(const QStringList &filepaths) {
for (const auto &filepath : filepaths) {
ignoreWatchedFileTemporarily(filepath);
}
}
void Project::recordFileChange(const QString &filepath) {
if (this->modifiedFiles.contains(filepath)) {
// We already recorded a change to this file
@@ -1257,6 +1275,8 @@ bool Project::saveMap(Map *map, bool skipLayout) {
// Custom header fields.
OrderedJson::append(&mapObj, map->customAttributes());
ignoreWatchedFileTemporarily(mapFilepath);
OrderedJson mapJson(mapObj);
OrderedJsonDoc jsonDoc(&mapJson);
jsonDoc.dump(&mapFile);
@@ -1456,12 +1476,25 @@ Tileset *Project::createNewTileset(QString name, bool secondary, bool checkerboa
labelList->insert(i, tileset->name);
this->tilesetLabelsOrdered.append(tileset->name);
// Append to tileset specific files.
// TODO: Ideally we wouldn't save new Tilesets immediately
// Append to tileset specific files. Strip prefix from name to get base name for use in other symbols.
name.remove(0, prefix.length());
tileset->appendToHeaders(this->root, name, this->usingAsmTilesets);
tileset->appendToGraphics(this->root, name, this->usingAsmTilesets);
tileset->appendToMetatiles(this->root, name, this->usingAsmTilesets);
QString headersFilepath = this->root + "/";
QString graphicsFilepath = this->root + "/";
QString metatilesFilepath = this->root + "/";
if (this->usingAsmTilesets) {
headersFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm));
graphicsFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_graphics_asm));
metatilesFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles_asm));
} else {
headersFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_headers));
graphicsFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_graphics));
metatilesFilepath.append(projectConfig.getFilePath(ProjectFilePath::tilesets_metatiles));
}
ignoreWatchedFilesTemporarily({headersFilepath, graphicsFilepath, metatilesFilepath});
name.remove(0, prefix.length()); // Strip prefix from name to get base name for use in other symbols.
tileset->appendToHeaders(headersFilepath, name, this->usingAsmTilesets);
tileset->appendToGraphics(graphicsFilepath, name, this->usingAsmTilesets);
tileset->appendToMetatiles(metatilesFilepath, name, this->usingAsmTilesets);
tileset->save();
@@ -1485,7 +1518,7 @@ bool Project::readTilesetMetatileLabels() {
unusedMetatileLabels.clear();
QString metatileLabelsFilename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels);
fileWatcher.addPath(root + "/" + metatileLabelsFilename);
watchFile(metatileLabelsFilename);
const QSet<QString> regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix))};
const auto defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList);
@@ -1593,7 +1626,7 @@ bool Project::readWildMonData() {
const QString encounterRateFile = projectConfig.getFilePath(ProjectFilePath::wild_encounter);
const QString maxEncounterRateName = projectConfig.getIdentifier(ProjectIdentifier::define_max_encounter_rate);
fileWatcher.addPath(QString("%1/%2").arg(root).arg(encounterRateFile));
watchFile(encounterRateFile);
auto defines = parser.readCDefinesByName(encounterRateFile, {maxEncounterRateName});
if (defines.contains(maxEncounterRateName))
this->maxEncounterRate = defines.value(maxEncounterRateName)/16;
@@ -1602,8 +1635,7 @@ bool Project::readWildMonData() {
const QString levelRangeFile = projectConfig.getFilePath(ProjectFilePath::constants_pokemon);
const QString minLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_min_level);
const QString maxLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_max_level);
fileWatcher.addPath(QString("%1/%2").arg(root).arg(levelRangeFile));
watchFile(levelRangeFile);
defines = parser.readCDefinesByName(levelRangeFile, {minLevelName, maxLevelName});
if (defines.contains(minLevelName))
this->pokemonMinLevel = defines.value(minLevelName);
@@ -1615,7 +1647,7 @@ bool Project::readWildMonData() {
// Read encounter data
const QString wildMonJsonFilepath = projectConfig.getFilePath(ProjectFilePath::json_wild_encounters);
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(wildMonJsonFilepath));
watchFile(wildMonJsonFilepath);
OrderedJson::object wildMonObj;
QString error;
@@ -1772,7 +1804,7 @@ bool Project::readMapGroups() {
this->customMapGroupsData = QJsonObject();
const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_map_groups);
fileWatcher.addPath(root + "/" + filepath);
watchFile(filepath);
QJsonDocument mapGroupsDoc;
QString error;
if (!parser.tryParseJsonFile(&mapGroupsDoc, filepath, &error)) {
@@ -2075,7 +2107,7 @@ bool Project::readTilesetLabels() {
// If the tileset headers file is missing, the user may still have the old assembly format.
this->usingAsmTilesets = true;
QString asm_filename = projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm);
QString text = parser.readTextFile(this->root + "/" + asm_filename);
QString text = parser.loadTextFile(asm_filename);
if (text.isEmpty()) {
logError(QString("Failed to read tileset labels from '%1' or '%2'.").arg(filename).arg(asm_filename));
return false;
@@ -2122,7 +2154,7 @@ bool Project::readFieldmapProperties() {
const QString mapOffsetHeightName = projectConfig.getIdentifier(ProjectIdentifier::define_map_offset_height);
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
const auto defines = parser.readCDefinesByName(filename, { numTilesPrimaryName,
numTilesTotalName,
numMetatilesPrimaryName,
@@ -2226,8 +2258,7 @@ bool Project::readFieldmapMasks() {
const QString behaviorMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior);
const QString layerTypeMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer);
const QString globalFieldmap = projectConfig.getFilePath(ProjectFilePath::global_fieldmap);
fileWatcher.addPath(root + "/" + globalFieldmap);
const QString globalFieldmap = projectConfig.getFilePath(ProjectFilePath::global_fieldmap); // File already being watched
const auto defines = parser.readCDefinesByName(globalFieldmap, { metatileIdMaskName,
collisionMaskName,
elevationMaskName,
@@ -2282,7 +2313,7 @@ bool Project::readFieldmapMasks() {
const QString layerTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer);
const QString encounterTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter);
const QString terrainTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain);
fileWatcher.addPath(root + "/" + srcFieldmap);
watchFile(srcFieldmap);
bool ok;
// Read terrain type mask
@@ -2360,7 +2391,7 @@ bool Project::readRegionMapSections() {
logError(QString("Failed to read region map sections from '%1': %2").arg(filepath).arg(error));
return false;
}
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
watchFile(filepath);
QJsonObject mapSectionsGlobalObj = doc.object();
QJsonArray mapSections = mapSectionsGlobalObj.take("map_sections").toArray();
@@ -2524,7 +2555,7 @@ bool Project::readHealLocations() {
logError(QString("Failed to read heal locations from '%1': %2").arg(filepath).arg(error));
return false;
}
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
watchFile(filepath);
QJsonObject healLocationsObj = doc.object();
QJsonArray healLocations = healLocationsObj.take("heal_locations").toArray();
@@ -2547,7 +2578,7 @@ bool Project::readHealLocations() {
bool Project::readItemNames() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_items);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->itemNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_items)}, &error);
if (!error.isEmpty())
@@ -2557,7 +2588,7 @@ bool Project::readItemNames() {
bool Project::readFlagNames() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_flags);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->flagNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_flags)}, &error);
if (!error.isEmpty())
@@ -2567,7 +2598,7 @@ bool Project::readFlagNames() {
bool Project::readVarNames() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_vars);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->varNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_vars)}, &error);
if (!error.isEmpty())
@@ -2577,7 +2608,7 @@ bool Project::readVarNames() {
bool Project::readMovementTypes() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_event_movement);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->movementTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_movement_types)}, &error);
if (!error.isEmpty())
@@ -2587,7 +2618,7 @@ bool Project::readMovementTypes() {
bool Project::readInitialFacingDirections() {
QString filename = projectConfig.getFilePath(ProjectFilePath::initial_facing_table);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->facingDirections = parser.readNamedIndexCArray(filename, projectConfig.getIdentifier(ProjectIdentifier::symbol_facing_directions), &error);
if (!error.isEmpty())
@@ -2597,7 +2628,7 @@ bool Project::readInitialFacingDirections() {
bool Project::readMapTypes() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types);
fileWatcher.addPath(root + "/" + filename);
// File already being watched
QString error;
this->mapTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_map_types)}, &error);
if (!error.isEmpty())
@@ -2607,7 +2638,7 @@ bool Project::readMapTypes() {
bool Project::readMapBattleScenes() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types);
fileWatcher.addPath(root + "/" + filename);
// File already being watched
QString error;
this->mapBattleScenes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_battle_scenes)}, &error);
if (!error.isEmpty())
@@ -2617,7 +2648,7 @@ bool Project::readMapBattleScenes() {
bool Project::readWeatherNames() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->weatherNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_weather)}, &error);
if (!error.isEmpty())
@@ -2630,7 +2661,7 @@ bool Project::readCoordEventWeatherNames() {
return true;
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->coordEventWeatherNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)}, &error);
if (!error.isEmpty())
@@ -2643,7 +2674,7 @@ bool Project::readSecretBaseIds() {
return true;
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->secretBaseIds = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)}, &error);
if (!error.isEmpty())
@@ -2653,7 +2684,7 @@ bool Project::readSecretBaseIds() {
bool Project::readBgEventFacingDirections() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_event_bg);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->bgEventFacingDirections = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_sign_facing_directions)}, &error);
if (!error.isEmpty())
@@ -2663,7 +2694,7 @@ bool Project::readBgEventFacingDirections() {
bool Project::readTrainerTypes() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_trainer_types);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->trainerTypes = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_trainer_types)}, &error);
if (!error.isEmpty())
@@ -2676,7 +2707,7 @@ bool Project::readMetatileBehaviors() {
this->metatileBehaviorMapInverse.clear();
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_behaviors);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}, &error);
if (defines.isEmpty() && projectConfig.metatileBehaviorMask) {
@@ -2698,7 +2729,7 @@ bool Project::readMetatileBehaviors() {
bool Project::readSongNames() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_songs);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
this->songNames = parser.readCDefineNames(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_music)}, &error);
if (!error.isEmpty())
@@ -2713,7 +2744,7 @@ bool Project::readSongNames() {
bool Project::readObjEventGfxConstants() {
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
QString error;
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}, &error);
if (!error.isEmpty())
@@ -2729,7 +2760,7 @@ bool Project::readObjEventGfxConstants() {
bool Project::readMiscellaneousConstants() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_global);
const QString maxObjectEventsName = projectConfig.getIdentifier(ProjectIdentifier::define_obj_event_count);
fileWatcher.addPath(root + "/" + filename);
watchFile(filename);
const auto defines = parser.readCDefinesByName(filename, {maxObjectEventsName});
this->maxObjectEvents = 64; // Default value
@@ -2856,7 +2887,7 @@ bool Project::readEventGraphics() {
const QString gfxInfoFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_info);
const QString picTablesFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_pic_tables);
const QString gfxFilepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx);
fileWatcher.addPaths({pointersFilepath, gfxInfoFilepath, picTablesFilepath, gfxFilepath});
watchFiles({pointersFilepath, gfxInfoFilepath, picTablesFilepath, gfxFilepath});
// Read the table mapping OBJ_EVENT_GFX constants to the names of pointers to data about their graphics.
const QString pointersName = projectConfig.getIdentifier(ProjectIdentifier::symbol_obj_event_gfx_pointers);
@@ -3057,14 +3088,14 @@ bool Project::readSpeciesIconPaths() {
// Read map of species constants to icon names
const QString srcfilename = projectConfig.getFilePath(ProjectFilePath::pokemon_icon_table);
fileWatcher.addPath(this->root + "/" + srcfilename);
watchFile(srcfilename);
const QString tableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_pokemon_icon_table);
const QMap<QString, QString> monIconNames = parser.readNamedIndexCArray(srcfilename, tableName);
// Read species constants. If this fails we can get them from the icon table (but we shouldn't rely on it).
const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix);
const QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_species);
fileWatcher.addPath(this->root + "/" + constantsFilename);
watchFile(constantsFilename);
this->speciesNames = parser.readCDefineNames(constantsFilename, {QString("\\b%1").arg(speciesPrefix)});
if (this->speciesNames.isEmpty()) {
this->speciesNames = monIconNames.keys();
@@ -3077,7 +3108,7 @@ bool Project::readSpeciesIconPaths() {
// do this on request in Project::getDefaultSpeciesIconPath.
if (!monIconNames.isEmpty()) {
const QString iconGraphicsFile = projectConfig.getFilePath(ProjectFilePath::data_pokemon_gfx);
fileWatcher.addPath(this->root + "/" + iconGraphicsFile);
watchFile(iconGraphicsFile);
QMap<QString, QString> iconNameToFilepath = parser.readCIncbinMulti(iconGraphicsFile);
for (auto i = monIconNames.constBegin(); i != monIconNames.constEnd(); i++) {