Finish mounting feature
To pull this one off, a new class called VPath was created that denotes "virtual" paths that can exist anywhere among the list of mount points. It is functionally identical to QString, except that implicit conversion between QString and VPath is not allowed. This makes it easy to spot errors in path resolution at compile time, since get_real_path must be called to resolve a VPath into an absolute path that can be passed into a Qt function as a QString. Other functions, such as the get_*_suffix functions, also return an absolute path QString for convenience. As for the rest of the functions that return a VPath, you will need to call get_real_path yourself. Finally, a path resolution cache was added to try to avoid blowing up what is already a massive lookup cost for assets. The cache is invalidated when the mount path list is changed. Currently, this cache isn't bounded. Might need to write an LRU cache if issues arise.
This commit is contained in:
parent
a023657348
commit
d27501313c
@ -37,6 +37,25 @@ class NetworkManager;
|
||||
class Lobby;
|
||||
class Courtroom;
|
||||
|
||||
class VPath : QString {
|
||||
using QString::QString;
|
||||
|
||||
public:
|
||||
explicit VPath(const QString &str) : QString(str) {}
|
||||
inline QString const &toQString() const { return *this; }
|
||||
inline bool operator==(const VPath &str) const {
|
||||
return this->toQString() == str.toQString();
|
||||
}
|
||||
inline VPath operator+(const VPath &str) const {
|
||||
return VPath(this->toQString() + str.toQString());
|
||||
}
|
||||
};
|
||||
|
||||
inline uint qHash(const VPath &key, uint seed)
|
||||
{
|
||||
return qHash(key.toQString(), seed);
|
||||
}
|
||||
|
||||
class AOApplication : public QApplication {
|
||||
Q_OBJECT
|
||||
|
||||
@ -130,23 +149,25 @@ public:
|
||||
|
||||
// implementation in path_functions.cpp
|
||||
QString get_base_path();
|
||||
QString get_theme_path(QString p_file, QString p_theme="");
|
||||
QString get_character_path(QString p_char, QString p_file);
|
||||
QString get_misc_path(QString p_misc, QString p_file);
|
||||
QString get_sounds_path(QString p_file);
|
||||
QString get_music_path(QString p_song);
|
||||
QString get_background_path(QString p_file);
|
||||
QString get_default_background_path(QString p_file);
|
||||
QString get_evidence_path(QString p_file);
|
||||
QStringList get_asset_paths(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="");
|
||||
QString get_asset_path(QStringList pathlist);
|
||||
QString get_image_path(QStringList pathlist, bool static_image=false);
|
||||
QString get_sfx_path(QStringList pathlist);
|
||||
VPath get_theme_path(QString p_file, QString p_theme="");
|
||||
VPath get_character_path(QString p_char, QString p_file);
|
||||
VPath get_misc_path(QString p_misc, QString p_file);
|
||||
VPath get_sounds_path(QString p_file);
|
||||
VPath get_music_path(QString p_song);
|
||||
VPath get_background_path(QString p_file);
|
||||
VPath get_default_background_path(QString p_file);
|
||||
VPath get_evidence_path(QString p_file);
|
||||
QVector<VPath> get_asset_paths(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="");
|
||||
QString get_asset_path(QVector<VPath> pathlist);
|
||||
QString get_image_path(QVector<VPath> pathlist, bool static_image=false);
|
||||
QString get_sfx_path(QVector<VPath> pathlist);
|
||||
QString get_config_value(QString p_identifier, QString p_config, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="");
|
||||
QString get_asset(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="");
|
||||
QString get_image(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="");
|
||||
QString get_image(QString p_element, QString p_theme="", QString p_subtheme="", QString p_default_theme="", QString p_misc="", QString p_character="", QString p_placeholder="", bool static_image=false);
|
||||
QString get_sfx(QString p_sfx, QString p_misc="", QString p_character="");
|
||||
QString get_case_sensitive_path(QString p_file);
|
||||
QString get_real_path(const VPath &vpath);
|
||||
void invalidate_lookup_cache();
|
||||
|
||||
////// Functions for reading and writing files //////
|
||||
// Implementations file_functions.cpp
|
||||
@ -281,6 +302,7 @@ public:
|
||||
QStringList get_call_words();
|
||||
|
||||
// returns all of the file's lines in a QStringList
|
||||
QStringList get_list_file(VPath path);
|
||||
QStringList get_list_file(QString p_file);
|
||||
|
||||
// Process a file and return its text as a QString
|
||||
@ -304,6 +326,7 @@ public:
|
||||
QVector<server_type> read_serverlist_txt();
|
||||
|
||||
// Returns the value of p_identifier in the design.ini file in p_design_path
|
||||
QString read_design_ini(QString p_identifier, VPath p_design_path);
|
||||
QString read_design_ini(QString p_identifier, QString p_design_path);
|
||||
|
||||
// Returns the coordinates of widget with p_identifier from p_file
|
||||
@ -332,19 +355,22 @@ public:
|
||||
// Returns the sfx with p_identifier from courtroom_sounds.ini in the current theme path
|
||||
QString get_court_sfx(QString p_identifier, QString p_misc="");
|
||||
|
||||
// Find the correct suffix for a given file
|
||||
QString get_suffix(VPath file_to_check, QStringList suffixes);
|
||||
|
||||
// Figure out if we can opus this or if we should fall back to wav
|
||||
QString get_sfx_suffix(QString sound_to_check);
|
||||
QString get_sfx_suffix(VPath sound_to_check);
|
||||
|
||||
// Can we use APNG for this? If not, WEBP? If not, GIF? If not, fall back to
|
||||
// PNG.
|
||||
QString get_image_suffix(QString path_to_check, bool static_image=false);
|
||||
QString get_image_suffix(VPath path_to_check, bool static_image=false);
|
||||
|
||||
// Returns the value of p_search_line within target_tag and terminator_tag
|
||||
QString read_char_ini(QString p_char, QString p_search_line,
|
||||
QString target_tag);
|
||||
|
||||
// Returns a QStringList of all key=value definitions on a given tag.
|
||||
QStringList read_ini_tags(QString p_file, QString target_tag = "");
|
||||
QStringList read_ini_tags(VPath p_file, QString target_tag = "");
|
||||
|
||||
// Sets the char.ini p_search_line key under tag target_tag to value.
|
||||
void set_char_ini(QString p_char, QString value, QString p_search_line,
|
||||
@ -489,6 +515,9 @@ public:
|
||||
// Get if the theme is animated
|
||||
bool get_animated_theme();
|
||||
|
||||
// Get a list of custom mount paths
|
||||
QStringList get_mount_paths();
|
||||
|
||||
// Currently defined subtheme
|
||||
QString subtheme;
|
||||
|
||||
@ -514,6 +543,7 @@ private:
|
||||
|
||||
QVector<server_type> server_list;
|
||||
QVector<server_type> favorite_list;
|
||||
QHash<VPath, QString> asset_lookup_cache;
|
||||
|
||||
private slots:
|
||||
void ms_connect_finished(bool connected, bool will_retry);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <QBitmap>
|
||||
|
||||
class AOApplication;
|
||||
class VPath;
|
||||
|
||||
// "Brief" explanation of what the hell this is:
|
||||
//
|
||||
|
@ -180,6 +180,9 @@ private:
|
||||
QPushButton *ui_mount_remove;
|
||||
QPushButton *ui_mount_up;
|
||||
QPushButton *ui_mount_down;
|
||||
QPushButton *ui_mount_clear_cache;
|
||||
|
||||
bool asset_cache_dirty = false;
|
||||
|
||||
bool needs_default_audiodev();
|
||||
void update_values();
|
||||
|
@ -19,6 +19,7 @@ AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv)
|
||||
QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)),
|
||||
SLOT(ms_connect_finished(bool, bool)));
|
||||
// qApp->setStyleSheet("QFrame {background-color:transparent;} QAbstractItemView {background-color: transparent; color: black;}; QLineEdit {background-color:transparent;}");
|
||||
asset_lookup_cache.reserve(2048);
|
||||
}
|
||||
|
||||
AOApplication::~AOApplication()
|
||||
|
@ -27,7 +27,7 @@ void AOButton::set_image(QString p_path, QString p_misc)
|
||||
else
|
||||
// Grab a static variant of the image
|
||||
p_image = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true);
|
||||
if (!file_exists(p_image)) {
|
||||
if (p_image.isEmpty()) {
|
||||
this->setIcon(QIcon());
|
||||
this->setIconSize(this->size());
|
||||
this->setStyleSheet("");
|
||||
|
@ -32,7 +32,7 @@ AOEvidenceButton::AOEvidenceButton(QWidget *p_parent, AOApplication *p_ao_app,
|
||||
|
||||
void AOEvidenceButton::set_image(QString p_image)
|
||||
{
|
||||
QString image_path = ao_app->get_evidence_path(p_image);
|
||||
QString image_path = ao_app->get_real_path(ao_app->get_evidence_path(p_image));
|
||||
if (file_exists(p_image)) {
|
||||
this->setText("");
|
||||
this->setStyleSheet(
|
||||
@ -57,8 +57,10 @@ void AOEvidenceButton::set_image(QString p_image)
|
||||
|
||||
void AOEvidenceButton::set_theme_image(QString p_image)
|
||||
{
|
||||
QString theme_image_path = ao_app->get_theme_path(p_image);
|
||||
QString default_image_path = ao_app->get_theme_path(p_image, ao_app->default_theme);
|
||||
QString theme_image_path = ao_app->get_real_path(
|
||||
ao_app->get_theme_path(p_image));
|
||||
QString default_image_path = ao_app->get_real_path(
|
||||
ao_app->get_theme_path(p_image, ao_app->default_theme));
|
||||
|
||||
QString final_image_path;
|
||||
|
||||
|
@ -35,7 +35,8 @@ void AOEvidenceDisplay::show_evidence(QString p_evidence_image,
|
||||
gif_name = "evidence_appear_right";
|
||||
}
|
||||
|
||||
QString f_evidence_path = ao_app->get_evidence_path(p_evidence_image);
|
||||
QString f_evidence_path = ao_app->get_real_path(
|
||||
ao_app->get_evidence_path(p_evidence_image));
|
||||
QPixmap f_pixmap(f_evidence_path);
|
||||
|
||||
pos_size_type icon_dimensions =
|
||||
|
@ -20,21 +20,16 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app) : QLabel(parent)
|
||||
|
||||
AOImage::~AOImage() {}
|
||||
|
||||
bool AOImage::set_image(QString p_path, QString p_misc)
|
||||
bool AOImage::set_image(QString p_image, QString p_misc)
|
||||
{
|
||||
// Check if the user wants animated themes
|
||||
if (ao_app->get_animated_theme())
|
||||
// We want an animated image
|
||||
p_path = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc);
|
||||
else
|
||||
// Grab a static variant of the image
|
||||
p_path = ao_app->get_image_path(ao_app->get_asset_paths(p_path, ao_app->current_theme, ao_app->get_subtheme(), ao_app->default_theme, p_misc), true);
|
||||
p_image = ao_app->get_image(p_image, ao_app->current_theme, ao_app->get_subtheme(),
|
||||
ao_app->default_theme, p_misc, "", "", !ao_app->get_animated_theme());
|
||||
|
||||
if (!file_exists(p_path)) {
|
||||
qDebug() << "Warning: Image" << p_path << "not found! Can't set!";
|
||||
if (!file_exists(p_image)) {
|
||||
qDebug() << "Warning: Image" << p_image << "not found! Can't set!";
|
||||
return false;
|
||||
}
|
||||
path = p_path;
|
||||
path = p_image;
|
||||
movie->stop();
|
||||
movie->setFileName(path);
|
||||
if (ao_app->get_animated_theme() && movie->frameCount() > 1) {
|
||||
|
@ -137,7 +137,7 @@ void BackgroundLayer::load_image(QString p_filename)
|
||||
{
|
||||
play_once = false;
|
||||
cull_image = false;
|
||||
QString design_path = ao_app->get_background_path("design.ini");
|
||||
VPath design_path = ao_app->get_background_path("design.ini");
|
||||
transform_mode =
|
||||
ao_app->get_scaling(ao_app->read_design_ini("scaling", design_path));
|
||||
stretch = ao_app->read_design_ini("stretch", design_path).startsWith("true");
|
||||
|
@ -19,7 +19,7 @@ void AOMusicPlayer::play(QString p_song, int channel, bool loop,
|
||||
channel = channel % m_channelmax;
|
||||
if (channel < 0) // wtf?
|
||||
return;
|
||||
QString f_path = ao_app->get_music_path(p_song);
|
||||
QString f_path = ao_app->get_real_path(ao_app->get_music_path(p_song));
|
||||
|
||||
unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE |
|
||||
BASS_UNICODE | BASS_ASYNCFILE;
|
||||
|
@ -14,7 +14,7 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
// Setting up the basics.
|
||||
setWindowFlag(Qt::WindowCloseButtonHint);
|
||||
setWindowTitle(tr("Settings"));
|
||||
resize(400, 408);
|
||||
resize(450, 408);
|
||||
|
||||
ui_settings_buttons = new QDialogButtonBox(this);
|
||||
|
||||
@ -907,7 +907,12 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
QFileDialog::ShowDirsOnly);
|
||||
if (dir.isEmpty())
|
||||
return;
|
||||
ui_mount_list->addItem(dir);
|
||||
QListWidgetItem *dir_item = new QListWidgetItem(dir);
|
||||
ui_mount_list->addItem(dir_item);
|
||||
ui_mount_list->setCurrentItem(dir_item);
|
||||
|
||||
// quick hack to update buttons
|
||||
emit ui_mount_list->itemSelectionChanged();
|
||||
});
|
||||
|
||||
ui_mount_remove = new QPushButton(tr("Remove"), ui_assets_tab);
|
||||
@ -918,7 +923,9 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
auto selected = ui_mount_list->selectedItems();
|
||||
if (selected.isEmpty())
|
||||
return;
|
||||
ui_mount_list->removeItemWidget(selected[0]);
|
||||
delete selected[0];
|
||||
emit ui_mount_list->itemSelectionChanged();
|
||||
asset_cache_dirty = true;
|
||||
});
|
||||
|
||||
auto *mount_buttons_spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding,
|
||||
@ -934,7 +941,13 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
auto selected = ui_mount_list->selectedItems();
|
||||
if (selected.isEmpty())
|
||||
return;
|
||||
ui_mount_list->setEditTriggers()
|
||||
auto *item = selected[0];
|
||||
int row = ui_mount_list->row(item);
|
||||
ui_mount_list->takeItem(row);
|
||||
int new_row = qMax(1, row - 1);
|
||||
ui_mount_list->insertItem(new_row, item);
|
||||
ui_mount_list->setCurrentRow(new_row);
|
||||
asset_cache_dirty = true;
|
||||
});
|
||||
|
||||
ui_mount_down = new QPushButton(tr("↓"), ui_assets_tab);
|
||||
@ -942,6 +955,49 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
|
||||
ui_mount_down->setMaximumWidth(40);
|
||||
ui_mount_down->setEnabled(false);
|
||||
ui_mount_buttons_layout->addWidget(ui_mount_down, 0, 4, 1, 1);
|
||||
connect(ui_mount_down, &QPushButton::clicked, this, [=] {
|
||||
auto selected = ui_mount_list->selectedItems();
|
||||
if (selected.isEmpty())
|
||||
return;
|
||||
auto *item = selected[0];
|
||||
int row = ui_mount_list->row(item);
|
||||
ui_mount_list->takeItem(row);
|
||||
int new_row = qMin(ui_mount_list->count() + 1, row + 1);
|
||||
ui_mount_list->insertItem(new_row, item);
|
||||
ui_mount_list->setCurrentRow(new_row);
|
||||
asset_cache_dirty = true;
|
||||
});
|
||||
|
||||
auto *mount_buttons_spacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding,
|
||||
QSizePolicy::Minimum);
|
||||
ui_mount_buttons_layout->addItem(mount_buttons_spacer_2, 0, 5, 1, 1);
|
||||
|
||||
ui_mount_clear_cache = new QPushButton(tr("Clear Cache"), ui_assets_tab);
|
||||
ui_mount_clear_cache->setToolTip(tr("Clears the lookup cache for assets. "
|
||||
"Use this when you have added an asset that takes precedence over another "
|
||||
"existing asset."));
|
||||
ui_mount_buttons_layout->addWidget(ui_mount_clear_cache, 0, 6, 1, 1);
|
||||
connect(ui_mount_clear_cache, &QPushButton::clicked, this, [=] {
|
||||
asset_cache_dirty = true;
|
||||
ui_mount_clear_cache->setEnabled(false);
|
||||
});
|
||||
|
||||
connect(ui_mount_list, &QListWidget::itemSelectionChanged, this, [=] {
|
||||
auto selected_items = ui_mount_list->selectedItems();
|
||||
bool row_selected = !ui_mount_list->selectedItems().isEmpty();
|
||||
ui_mount_remove->setEnabled(row_selected);
|
||||
ui_mount_up->setEnabled(row_selected);
|
||||
ui_mount_down->setEnabled(row_selected);
|
||||
|
||||
if (!row_selected)
|
||||
return;
|
||||
|
||||
int row = ui_mount_list->row(selected_items[0]);
|
||||
if (row <= 1)
|
||||
ui_mount_up->setEnabled(false);
|
||||
if (row >= ui_mount_list->count() - 1)
|
||||
ui_mount_down->setEnabled(false);
|
||||
});
|
||||
|
||||
update_values();
|
||||
|
||||
@ -1019,6 +1075,7 @@ void AOOptionsDialog::update_values() {
|
||||
.arg(ao_app->get_base_path()));
|
||||
defaultMount->setFlags(Qt::ItemFlag::NoItemFlags);
|
||||
ui_mount_list->addItem(defaultMount);
|
||||
ui_mount_list->addItems(ao_app->get_mount_paths());
|
||||
}
|
||||
|
||||
void AOOptionsDialog::save_pressed()
|
||||
@ -1091,9 +1148,17 @@ void AOOptionsDialog::save_pressed()
|
||||
configini->setValue("casing_can_host_cases",
|
||||
ui_casing_cm_cases_textbox->text());
|
||||
|
||||
QStringList mountPaths;
|
||||
for (int i = 1; i < ui_mount_list->count(); i++)
|
||||
mountPaths.append(ui_mount_list->item(i)->text());
|
||||
configini->setValue("mount_paths", mountPaths);
|
||||
|
||||
if (audioChanged)
|
||||
ao_app->initBASS();
|
||||
|
||||
if (asset_cache_dirty)
|
||||
ao_app->invalidate_lookup_cache();
|
||||
|
||||
callwordsini->close();
|
||||
|
||||
// We most probably pressed "Restore defaults" at some point. Since we're saving our settings, remove the temporary file.
|
||||
|
@ -157,8 +157,8 @@ void Courtroom::char_clicked(int n_char)
|
||||
{
|
||||
if (n_char != -1)
|
||||
{
|
||||
QString char_ini_path =
|
||||
ao_app->get_character_path(char_list.at(n_char).name, "char.ini");
|
||||
QString char_ini_path = ao_app->get_real_path(
|
||||
ao_app->get_character_path(char_list.at(n_char).name, "char.ini"));
|
||||
|
||||
qDebug() << "char_ini_path" << char_ini_path;
|
||||
|
||||
|
@ -501,7 +501,7 @@ void Courtroom::set_widgets()
|
||||
{
|
||||
QString filename = "courtroom_design.ini";
|
||||
// Update the default theme from the courtroom_design.ini, if it's not defined it will be 'default'.
|
||||
QSettings settings(ao_app->get_theme_path(filename, ao_app->current_theme), QSettings::IniFormat);
|
||||
QSettings settings(ao_app->get_real_path(ao_app->get_theme_path(filename, ao_app->current_theme)), QSettings::IniFormat);
|
||||
ao_app->default_theme = settings.value("default_theme", "default").toString();
|
||||
|
||||
set_fonts();
|
||||
@ -1384,11 +1384,11 @@ void Courtroom::update_character(int p_cid)
|
||||
custom_obj_menu->setDefaultAction(action);
|
||||
objection_custom = "";
|
||||
}
|
||||
if (dir_exists(
|
||||
ao_app->get_character_path(current_char, "custom_objections"))) {
|
||||
ui_custom_objection->show();
|
||||
QDir directory(
|
||||
QString custom_objection_dir = ao_app->get_real_path(
|
||||
ao_app->get_character_path(current_char, "custom_objections"));
|
||||
if (dir_exists(custom_objection_dir)) {
|
||||
ui_custom_objection->show();
|
||||
QDir directory(custom_objection_dir);
|
||||
QStringList custom_obj = directory.entryList(QStringList() << "*.png"
|
||||
<< "*.gif"
|
||||
<< "*.apng"
|
||||
@ -1523,7 +1523,7 @@ void Courtroom::list_music()
|
||||
treeItem->setText(0, i_song_listname);
|
||||
treeItem->setText(1, i_song);
|
||||
|
||||
QString song_path = ao_app->get_music_path(i_song);
|
||||
QString song_path = ao_app->get_real_path(ao_app->get_music_path(i_song));
|
||||
|
||||
if (file_exists(song_path))
|
||||
treeItem->setBackground(0, found_brush);
|
||||
@ -4333,8 +4333,9 @@ void Courtroom::set_iniswap_dropdown()
|
||||
ui_iniswap_remove->hide();
|
||||
return;
|
||||
}
|
||||
QStringList iniswaps = ao_app->get_list_file(
|
||||
ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")) + ao_app->get_list_file(ao_app->get_base_path() + "iniswaps.ini");
|
||||
QStringList iniswaps =
|
||||
ao_app->get_list_file(ao_app->get_character_path(char_list.at(m_cid).name, "iniswaps.ini")) +
|
||||
ao_app->get_list_file(ao_app->get_base_path() + "iniswaps.ini");
|
||||
iniswaps.removeDuplicates();
|
||||
iniswaps.prepend(char_list.at(m_cid).name);
|
||||
if (iniswaps.size() <= 0) {
|
||||
@ -4390,7 +4391,8 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos)
|
||||
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menu->addSeparator();
|
||||
if (file_exists(ao_app->get_character_path(current_char, "char.ini")))
|
||||
if (file_exists(ao_app->get_real_path(
|
||||
ao_app->get_character_path(current_char, "char.ini"))))
|
||||
menu->addAction(QString("Edit " + current_char + "/char.ini"), this,
|
||||
SLOT(on_iniswap_edit_requested()));
|
||||
if (ui_iniswap_dropdown->itemText(ui_iniswap_dropdown->currentIndex()) !=
|
||||
@ -4401,7 +4403,7 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos)
|
||||
}
|
||||
void Courtroom::on_iniswap_edit_requested()
|
||||
{
|
||||
QString p_path = ao_app->get_character_path(current_char, "char.ini");
|
||||
QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "char.ini"));
|
||||
if (!file_exists(p_path))
|
||||
return;
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(p_path));
|
||||
@ -4478,7 +4480,8 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos)
|
||||
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menu->addSeparator();
|
||||
if (file_exists(ao_app->get_character_path(current_char, "soundlist.ini")))
|
||||
if (file_exists(ao_app->get_real_path(
|
||||
ao_app->get_character_path(current_char, "soundlist.ini"))))
|
||||
menu->addAction(QString("Edit " + current_char + "/soundlist.ini"), this,
|
||||
SLOT(on_sfx_edit_requested()));
|
||||
else
|
||||
@ -4491,7 +4494,7 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos)
|
||||
|
||||
void Courtroom::on_sfx_edit_requested()
|
||||
{
|
||||
QString p_path = ao_app->get_character_path(current_char, "soundlist.ini");
|
||||
QString p_path = ao_app->get_real_path(ao_app->get_character_path(current_char, "soundlist.ini"));
|
||||
if (!file_exists(p_path)) {
|
||||
p_path = ao_app->get_base_path() + "soundlist.ini";
|
||||
}
|
||||
@ -4527,12 +4530,11 @@ void Courtroom::set_effects_dropdown()
|
||||
|
||||
// ICON-MAKING HELL
|
||||
QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options");
|
||||
QString custom_path =
|
||||
ao_app->get_base_path() + "misc/" + p_effect + "/icons/";
|
||||
QString theme_path = ao_app->get_theme_path("effects/icons/");
|
||||
QString default_path = ao_app->get_theme_path("effects/icons/", "default");
|
||||
VPath custom_path("misc/" + p_effect + "/icons/");
|
||||
VPath theme_path = ao_app->get_theme_path("effects/icons/");
|
||||
VPath default_path = ao_app->get_theme_path("effects/icons/", "default");
|
||||
for (int i = 0; i < ui_effects_dropdown->count(); ++i) {
|
||||
QString entry = ui_effects_dropdown->itemText(i);
|
||||
VPath entry = VPath(ui_effects_dropdown->itemText(i));
|
||||
QString iconpath = ao_app->get_image_suffix(custom_path + entry);
|
||||
if (!file_exists(iconpath)) {
|
||||
iconpath = ao_app->get_image_suffix(theme_path + entry);
|
||||
@ -4566,9 +4568,9 @@ void Courtroom::on_effects_context_menu_requested(const QPoint &pos)
|
||||
}
|
||||
void Courtroom::on_effects_edit_requested()
|
||||
{
|
||||
QString p_path = ao_app->get_theme_path("effects/");
|
||||
QString p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/"));
|
||||
if (!dir_exists(p_path)) {
|
||||
p_path = ao_app->get_theme_path("effects/", "default");
|
||||
p_path = ao_app->get_real_path(ao_app->get_theme_path("effects/", "default"));
|
||||
if (!dir_exists(p_path)) {
|
||||
return;
|
||||
}
|
||||
@ -4578,7 +4580,7 @@ void Courtroom::on_effects_edit_requested()
|
||||
void Courtroom::on_character_effects_edit_requested()
|
||||
{
|
||||
QString p_effect = ao_app->read_char_ini(current_char, "effects", "Options");
|
||||
QString p_path = ao_app->get_base_path() + "misc/" + p_effect + "/";
|
||||
QString p_path = ao_app->get_real_path(VPath("misc/" + p_effect + "/"));
|
||||
if (!dir_exists(p_path))
|
||||
return;
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
bool file_exists(QString file_path)
|
||||
{
|
||||
if (file_path.isEmpty())
|
||||
return false;
|
||||
|
||||
QFileInfo check_file(file_path);
|
||||
|
||||
return check_file.exists() && check_file.isFile();
|
||||
|
@ -39,71 +39,58 @@ QString AOApplication::get_base_path()
|
||||
return base_path;
|
||||
}
|
||||
|
||||
QString AOApplication::get_theme_path(QString p_file, QString p_theme)
|
||||
VPath AOApplication::get_theme_path(QString p_file, QString p_theme)
|
||||
{
|
||||
if (p_theme == "")
|
||||
p_theme = current_theme;
|
||||
QString path = get_base_path() + "themes/" + p_theme + "/" + p_file;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("themes/" + p_theme + "/" + p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_character_path(QString p_char, QString p_file)
|
||||
VPath AOApplication::get_character_path(QString p_char, QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "characters/" + p_char + "/" + p_file;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("characters/" + p_char + "/" + p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_misc_path(QString p_misc, QString p_file)
|
||||
VPath AOApplication::get_misc_path(QString p_misc, QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "misc/" + p_misc + "/" + p_file;
|
||||
#ifndef CASE_SENSITIVE_FILESYSTEM
|
||||
return path;
|
||||
#else
|
||||
return get_case_sensitive_path(path);
|
||||
#endif
|
||||
return VPath("misc/" + p_misc + "/" + p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_sounds_path(QString p_file)
|
||||
VPath AOApplication::get_sounds_path(QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "sounds/general/" + p_file;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("sounds/general/" + p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_music_path(QString p_song)
|
||||
VPath AOApplication::get_music_path(QString p_song)
|
||||
{
|
||||
if (p_song.startsWith("http")) {
|
||||
return p_song; // url
|
||||
return VPath(p_song); // url
|
||||
}
|
||||
QString path = get_base_path() + "sounds/music/" + p_song;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("sounds/music/" + p_song);
|
||||
}
|
||||
|
||||
QString AOApplication::get_background_path(QString p_file)
|
||||
VPath AOApplication::get_background_path(QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "background/" +
|
||||
w_courtroom->get_current_background() + "/" + p_file;
|
||||
if (courtroom_constructed) {
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("background/" + w_courtroom->get_current_background() + "/" + p_file);
|
||||
}
|
||||
return get_default_background_path(p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_default_background_path(QString p_file)
|
||||
VPath AOApplication::get_default_background_path(QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "background/default/" + p_file;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("background/default/" + p_file);
|
||||
}
|
||||
|
||||
QString AOApplication::get_evidence_path(QString p_file)
|
||||
VPath AOApplication::get_evidence_path(QString p_file)
|
||||
{
|
||||
QString path = get_base_path() + "evidence/" + p_file;
|
||||
return get_case_sensitive_path(path);
|
||||
return VPath("evidence/" + p_file);
|
||||
}
|
||||
|
||||
QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder)
|
||||
QVector<VPath> AOApplication::get_asset_paths(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder)
|
||||
{
|
||||
QStringList pathlist;
|
||||
pathlist += p_element; // The path by itself
|
||||
QVector<VPath> pathlist;
|
||||
pathlist += VPath(p_element); // The path by itself
|
||||
if (p_character != "")
|
||||
pathlist += get_character_path(p_character, p_element); // Character folder
|
||||
if (p_misc != "" && p_theme != "" && p_subtheme != "")
|
||||
@ -125,52 +112,47 @@ QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, Q
|
||||
return pathlist;
|
||||
}
|
||||
|
||||
QString AOApplication::get_asset_path(QStringList pathlist)
|
||||
QString AOApplication::get_asset_path(QVector<VPath> pathlist)
|
||||
{
|
||||
QString path;
|
||||
for (QString p : pathlist) {
|
||||
p = get_case_sensitive_path(p);
|
||||
if (file_exists(p)) {
|
||||
path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const VPath &p : pathlist) {
|
||||
QString path = get_real_path(p);
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AOApplication::get_image_path(QStringList pathlist, bool static_image)
|
||||
QString AOApplication::get_image_path(QVector<VPath> pathlist, bool static_image)
|
||||
{
|
||||
QString path;
|
||||
for (QString p : pathlist) {
|
||||
p = get_case_sensitive_path(get_image_suffix(p, static_image));
|
||||
if (file_exists(p)) {
|
||||
path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const VPath &p : pathlist) {
|
||||
QString path = get_image_suffix(p, static_image);
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AOApplication::get_sfx_path(QStringList pathlist)
|
||||
QString AOApplication::get_sfx_path(QVector<VPath> pathlist)
|
||||
{
|
||||
QString path;
|
||||
for (QString p : pathlist) {
|
||||
p = get_case_sensitive_path(get_sfx_suffix(p));
|
||||
if (file_exists(p)) {
|
||||
path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const VPath &p : pathlist) {
|
||||
QString path = get_sfx_suffix(p);
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AOApplication::get_config_value(QString p_identifier, QString p_config, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc)
|
||||
{
|
||||
QString path;
|
||||
// qDebug() << "got request for" << p_identifier << "in" << p_config;
|
||||
for (QString p : get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc)) {
|
||||
p = get_case_sensitive_path(p);
|
||||
if (file_exists(p)) {
|
||||
QSettings settings(p, QSettings::IniFormat);
|
||||
for (const VPath &p : get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc)) {
|
||||
path = get_real_path(p);
|
||||
if (!path.isEmpty()) {
|
||||
QSettings settings(path, QSettings::IniFormat);
|
||||
QVariant value = settings.value(p_identifier);
|
||||
if (value.type() == QVariant::StringList) {
|
||||
// qDebug() << "got" << p << "is a string list, returning" << value.toStringList().join(",");
|
||||
@ -190,24 +172,21 @@ QString AOApplication::get_asset(QString p_element, QString p_theme, QString p_s
|
||||
return get_asset_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder));
|
||||
}
|
||||
|
||||
QString AOApplication::get_image(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder)
|
||||
QString AOApplication::get_image(QString p_element, QString p_theme, QString p_subtheme, QString p_default_theme, QString p_misc, QString p_character, QString p_placeholder,
|
||||
bool static_image)
|
||||
{
|
||||
return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder));
|
||||
return get_image_path(get_asset_paths(p_element, p_theme, p_subtheme, p_default_theme, p_misc, p_character, p_placeholder), static_image);
|
||||
}
|
||||
|
||||
QString AOApplication::get_sfx(QString p_sfx, QString p_misc, QString p_character)
|
||||
{
|
||||
QStringList pathlist = get_asset_paths(p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character);
|
||||
QVector<VPath> pathlist = get_asset_paths(p_sfx, current_theme, get_subtheme(), default_theme, p_misc, p_character);
|
||||
pathlist += get_sounds_path(p_sfx); // Sounds folder path
|
||||
return get_sfx_path(pathlist);
|
||||
}
|
||||
|
||||
QString AOApplication::get_case_sensitive_path(QString p_file)
|
||||
{
|
||||
// no path traversal above base folder
|
||||
if (!(p_file.startsWith(get_base_path())))
|
||||
return get_base_path() + p_file;
|
||||
|
||||
#ifdef CASE_SENSITIVE_FILESYSTEM
|
||||
// first, check to see if it's actually there (also serves as base case for
|
||||
// recursion)
|
||||
@ -238,3 +217,35 @@ QString AOApplication::get_case_sensitive_path(QString p_file)
|
||||
return p_file;
|
||||
#endif
|
||||
}
|
||||
|
||||
QString AOApplication::get_real_path(const VPath &vpath) {
|
||||
// Try cache first
|
||||
QString phys_path = asset_lookup_cache.value(vpath);
|
||||
if (!phys_path.isEmpty() && exists(phys_path)) {
|
||||
return phys_path;
|
||||
}
|
||||
|
||||
// Cache miss; try all known mount paths
|
||||
QStringList bases = get_mount_paths();
|
||||
bases.push_front(get_base_path());
|
||||
|
||||
for (const QString &base : bases) {
|
||||
QDir baseDir(base);
|
||||
const QString path = baseDir.absoluteFilePath(vpath.toQString());
|
||||
if (!path.startsWith(baseDir.absolutePath())) {
|
||||
qWarning() << "invalid path" << path << "(path is outside vfs)";
|
||||
break;
|
||||
}
|
||||
if (exists(get_case_sensitive_path(path))) {
|
||||
asset_lookup_cache.insert(vpath, path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// File or directory not found
|
||||
return QString();
|
||||
}
|
||||
|
||||
void AOApplication::invalidate_lookup_cache() {
|
||||
asset_lookup_cache.clear();
|
||||
}
|
||||
|
@ -124,6 +124,11 @@ QStringList AOApplication::get_call_words()
|
||||
return get_list_file(get_base_path() + "callwords.ini");
|
||||
}
|
||||
|
||||
QStringList AOApplication::get_list_file(VPath path)
|
||||
{
|
||||
return get_list_file(get_real_path(path));
|
||||
}
|
||||
|
||||
QStringList AOApplication::get_list_file(QString p_file)
|
||||
{
|
||||
QStringList return_value;
|
||||
@ -275,6 +280,12 @@ QVector<server_type> AOApplication::read_serverlist_txt()
|
||||
return f_server_list;
|
||||
}
|
||||
|
||||
QString AOApplication::read_design_ini(QString p_identifier,
|
||||
VPath p_design_path)
|
||||
{
|
||||
return read_design_ini(p_identifier, get_real_path(p_design_path));
|
||||
}
|
||||
|
||||
QString AOApplication::read_design_ini(QString p_identifier,
|
||||
QString p_design_path)
|
||||
{
|
||||
@ -440,12 +451,14 @@ QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat)
|
||||
return value.toLatin1();
|
||||
|
||||
// Backwards ass compatibility
|
||||
QStringList backwards_paths{get_theme_path("misc/" + p_chat + "/config.ini"),
|
||||
get_base_path() + "misc/" + p_chat +
|
||||
"/config.ini",
|
||||
get_base_path() + "misc/default/config.ini",
|
||||
get_theme_path("misc/default/config.ini")};
|
||||
for (const QString &p : backwards_paths) {
|
||||
QVector<VPath> backwards_paths {
|
||||
get_theme_path("misc/" + p_chat + "/config.ini"),
|
||||
VPath("misc/" + p_chat + "/config.ini"),
|
||||
VPath("misc/default/config.ini"),
|
||||
get_theme_path("misc/default/config.ini")
|
||||
};
|
||||
|
||||
for (const VPath &p : backwards_paths) {
|
||||
QString value = read_design_ini(p_identifier, p);
|
||||
if (!value.isEmpty()) {
|
||||
return value.toLatin1();
|
||||
@ -482,36 +495,32 @@ QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc)
|
||||
return "";
|
||||
}
|
||||
|
||||
QString AOApplication::get_sfx_suffix(QString sound_to_check)
|
||||
{
|
||||
if (file_exists(sound_to_check))
|
||||
return sound_to_check;
|
||||
if (file_exists(sound_to_check + ".opus"))
|
||||
return sound_to_check + ".opus";
|
||||
if (file_exists(sound_to_check + ".ogg"))
|
||||
return sound_to_check + ".ogg";
|
||||
if (file_exists(sound_to_check + ".mp3"))
|
||||
return sound_to_check + ".mp3";
|
||||
if (file_exists(sound_to_check + ".mp4"))
|
||||
return sound_to_check + ".mp4";
|
||||
return sound_to_check + ".wav";
|
||||
QString AOApplication::get_suffix(VPath path_to_check, QStringList suffixes) {
|
||||
for (const QString &suffix : suffixes) {
|
||||
QString path = get_real_path(VPath(path_to_check.toQString() + suffix));
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
}
|
||||
|
||||
QString AOApplication::get_image_suffix(QString path_to_check, bool static_image)
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AOApplication::get_sfx_suffix(VPath sound_to_check)
|
||||
{
|
||||
if (file_exists(path_to_check))
|
||||
return path_to_check;
|
||||
return get_suffix(sound_to_check, { "", ".opus", ".ogg", ".mp3", ".wav" });
|
||||
}
|
||||
|
||||
QString AOApplication::get_image_suffix(VPath path_to_check, bool static_image)
|
||||
{
|
||||
QStringList suffixes { "" };
|
||||
// A better method would to actually use AOImageReader and see if these images have more than 1 frame.
|
||||
// However, that might not be performant.
|
||||
if (!static_image) {
|
||||
if (file_exists(path_to_check + ".webp"))
|
||||
return path_to_check + ".webp";
|
||||
if (file_exists(path_to_check + ".apng"))
|
||||
return path_to_check + ".apng";
|
||||
if (file_exists(path_to_check + ".gif"))
|
||||
return path_to_check + ".gif";
|
||||
suffixes.append({ ".webp", ".apng", ".gif" });
|
||||
}
|
||||
return path_to_check + ".png";
|
||||
suffixes.append(".png");
|
||||
|
||||
return get_suffix(path_to_check, suffixes);
|
||||
}
|
||||
|
||||
// returns whatever is to the right of "search_line =" within target_tag and
|
||||
@ -520,7 +529,7 @@ QString AOApplication::get_image_suffix(QString path_to_check, bool static_image
|
||||
QString AOApplication::read_char_ini(QString p_char, QString p_search_line,
|
||||
QString target_tag)
|
||||
{
|
||||
QSettings settings(get_character_path(p_char, "char.ini"),
|
||||
QSettings settings(get_real_path(get_character_path(p_char, "char.ini")),
|
||||
QSettings::IniFormat);
|
||||
settings.beginGroup(target_tag);
|
||||
QString value = settings.value(p_search_line).value<QString>();
|
||||
@ -531,7 +540,7 @@ QString AOApplication::read_char_ini(QString p_char, QString p_search_line,
|
||||
void AOApplication::set_char_ini(QString p_char, QString value,
|
||||
QString p_search_line, QString target_tag)
|
||||
{
|
||||
QSettings settings(get_character_path(p_char, "char.ini"),
|
||||
QSettings settings(get_real_path(get_character_path(p_char, "char.ini")),
|
||||
QSettings::IniFormat);
|
||||
settings.beginGroup(target_tag);
|
||||
settings.setValue(p_search_line, value);
|
||||
@ -539,10 +548,10 @@ void AOApplication::set_char_ini(QString p_char, QString value,
|
||||
}
|
||||
|
||||
// returns all the values of target_tag
|
||||
QStringList AOApplication::read_ini_tags(QString p_path, QString target_tag)
|
||||
QStringList AOApplication::read_ini_tags(VPath p_path, QString target_tag)
|
||||
{
|
||||
QStringList r_values;
|
||||
QSettings settings(p_path, QSettings::IniFormat);
|
||||
QSettings settings(get_real_path(p_path), QSettings::IniFormat);
|
||||
if (!target_tag.isEmpty())
|
||||
settings.beginGroup(target_tag);
|
||||
QStringList keys = settings.allKeys();
|
||||
@ -1084,3 +1093,8 @@ bool AOApplication::get_animated_theme()
|
||||
configini->value("animated_theme", "true").value<QString>();
|
||||
return result.startsWith("true");
|
||||
}
|
||||
|
||||
QStringList AOApplication::get_mount_paths()
|
||||
{
|
||||
return configini->value("mount_paths").value<QStringList>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user