Merge pull request #554 from AttorneyOnline/feature/mounting
Add support for mounting multiple base folders
This commit is contained in:
		
						commit
						9e0a964af8
					
				@ -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 = qGlobalQHashSeed())
 | 
			
		||||
{
 | 
			
		||||
  return qHash(key.toQString(), seed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class AOApplication : public QApplication {
 | 
			
		||||
  Q_OBJECT
 | 
			
		||||
 | 
			
		||||
@ -130,24 +149,26 @@ public:
 | 
			
		||||
 | 
			
		||||
  // implementation in path_functions.cpp
 | 
			
		||||
  QString get_base_path();
 | 
			
		||||
  QString get_data_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);
 | 
			
		||||
  QString get_real_suffixed_path(const VPath &vpath, const QStringList &suffixes);
 | 
			
		||||
  void invalidate_lookup_cache();
 | 
			
		||||
 | 
			
		||||
  ////// Functions for reading and writing files //////
 | 
			
		||||
  // Implementations file_functions.cpp
 | 
			
		||||
@ -285,6 +306,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
 | 
			
		||||
@ -308,6 +330,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
 | 
			
		||||
@ -337,18 +360,18 @@ public:
 | 
			
		||||
  QString get_court_sfx(QString p_identifier, QString p_misc="");
 | 
			
		||||
 | 
			
		||||
  // 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,
 | 
			
		||||
@ -492,6 +515,9 @@ public:
 | 
			
		||||
  // Get the default scaling method
 | 
			
		||||
  QString get_default_scaling();
 | 
			
		||||
 | 
			
		||||
  // Get a list of custom mount paths
 | 
			
		||||
  QStringList get_mount_paths();
 | 
			
		||||
 | 
			
		||||
  // Currently defined subtheme
 | 
			
		||||
  QString subtheme;
 | 
			
		||||
 | 
			
		||||
@ -527,6 +553,9 @@ private:
 | 
			
		||||
 | 
			
		||||
  QVector<server_type> server_list;
 | 
			
		||||
  QVector<server_type> favorite_list;
 | 
			
		||||
  QHash<uint, QString> asset_lookup_cache;
 | 
			
		||||
  QHash<uint, QString> dir_listing_cache;
 | 
			
		||||
  QSet<uint> dir_listing_exist_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:
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@
 | 
			
		||||
#include <QtWidgets/QWidget>
 | 
			
		||||
 | 
			
		||||
#include <QDirIterator>
 | 
			
		||||
#include <QListWidget>
 | 
			
		||||
#include <QTextStream>
 | 
			
		||||
 | 
			
		||||
class Lobby;
 | 
			
		||||
@ -174,6 +175,19 @@ private:
 | 
			
		||||
  QLabel *ui_log_lbl;
 | 
			
		||||
  QCheckBox *ui_log_cb;
 | 
			
		||||
 | 
			
		||||
  QWidget *ui_assets_tab;
 | 
			
		||||
  QVBoxLayout *ui_assets_tab_layout;
 | 
			
		||||
  QGridLayout *ui_mount_buttons_layout;
 | 
			
		||||
  QLabel *ui_asset_lbl;
 | 
			
		||||
  QListWidget *ui_mount_list;
 | 
			
		||||
  QPushButton *ui_mount_add;
 | 
			
		||||
  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();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,8 @@ AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv)
 | 
			
		||||
  discord = new AttorneyOnline::Discord();
 | 
			
		||||
  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()
 | 
			
		||||
 | 
			
		||||
@ -20,14 +20,9 @@ void AOButton::set_image(QString p_path, QString p_misc)
 | 
			
		||||
{
 | 
			
		||||
  movie->stop();
 | 
			
		||||
  QString p_image;
 | 
			
		||||
  // Check if the user wants animated themes
 | 
			
		||||
  if (ao_app->get_animated_theme())
 | 
			
		||||
    // We want an animated image
 | 
			
		||||
    p_image = 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_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)) {
 | 
			
		||||
  p_image = ao_app->get_image(p_path, ao_app->current_theme, ao_app->get_subtheme(),
 | 
			
		||||
                              ao_app->default_theme, p_misc, "", "", !ao_app->get_animated_theme());
 | 
			
		||||
  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 =
 | 
			
		||||
 | 
			
		||||
@ -24,21 +24,16 @@ AOImage::AOImage(QWidget *parent, AOApplication *p_ao_app, bool make_static) : Q
 | 
			
		||||
 | 
			
		||||
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 (!is_static && 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, "", "", is_static || !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;
 | 
			
		||||
  if (!is_static) {
 | 
			
		||||
    movie->stop();
 | 
			
		||||
    movie->setFileName(path);
 | 
			
		||||
 | 
			
		||||
@ -138,7 +138,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");
 | 
			
		||||
@ -197,7 +197,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname,
 | 
			
		||||
           << current_emote << " from character: " << p_charname
 | 
			
		||||
           << " continuous: " << continuous;
 | 
			
		||||
#endif
 | 
			
		||||
  QStringList pathlist = {
 | 
			
		||||
  QVector<VPath> pathlist {
 | 
			
		||||
      ao_app->get_character_path(
 | 
			
		||||
          p_charname, prefix + current_emote), // Default path
 | 
			
		||||
      ao_app->get_character_path(
 | 
			
		||||
@ -207,7 +207,7 @@ void CharLayer::load_image(QString p_filename, QString p_charname,
 | 
			
		||||
      ao_app->get_character_path(
 | 
			
		||||
          p_charname,
 | 
			
		||||
          current_emote), // Just use the non-prefixed image, animated or not
 | 
			
		||||
      current_emote, // The path by itself after the above fail
 | 
			
		||||
      VPath(current_emote), // The path by itself after the above fail
 | 
			
		||||
      ao_app->get_theme_path("placeholder"), // Theme placeholder path
 | 
			
		||||
      ao_app->get_theme_path(
 | 
			
		||||
          "placeholder", ao_app->default_theme)}; // Default theme placeholder path
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ int AOMusicPlayer::play(QString p_song, int channel, bool loop,
 | 
			
		||||
  channel = channel % m_channelmax;
 | 
			
		||||
  if (channel < 0) // wtf?
 | 
			
		||||
    return BASS_ERROR_NOCHAN;
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,8 @@
 | 
			
		||||
#include "lobby.h"
 | 
			
		||||
#include "bass.h"
 | 
			
		||||
 | 
			
		||||
#include <QFileDialog>
 | 
			
		||||
 | 
			
		||||
AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
 | 
			
		||||
    : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint)
 | 
			
		||||
{
 | 
			
		||||
@ -12,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);
 | 
			
		||||
 | 
			
		||||
@ -73,12 +75,19 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
 | 
			
		||||
  ui_theme_combobox = new QComboBox(ui_form_layout_widget);
 | 
			
		||||
 | 
			
		||||
  // Fill the combobox with the names of the themes.
 | 
			
		||||
  QDirIterator it(ao_app->get_base_path() + "themes", QDir::Dirs,
 | 
			
		||||
                  QDirIterator::NoIteratorFlags);
 | 
			
		||||
  while (it.hasNext()) {
 | 
			
		||||
    QString actualname = QDir(it.next()).dirName();
 | 
			
		||||
    if (actualname != "." && actualname != "..")
 | 
			
		||||
      ui_theme_combobox->addItem(actualname);
 | 
			
		||||
  QSet<QString> themes;
 | 
			
		||||
  QStringList bases = ao_app->get_mount_paths();
 | 
			
		||||
  bases.push_front(ao_app->get_base_path());
 | 
			
		||||
  for (const QString &base : bases) {
 | 
			
		||||
    QDirIterator it(base + "/themes", QDir::Dirs | QDir::NoDotAndDotDot,
 | 
			
		||||
                    QDirIterator::NoIteratorFlags);
 | 
			
		||||
    while (it.hasNext()) {
 | 
			
		||||
      QString actualname = QDir(it.next()).dirName();
 | 
			
		||||
      if (!themes.contains(actualname)) {
 | 
			
		||||
        ui_theme_combobox->addItem(actualname);
 | 
			
		||||
        themes.insert(actualname);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  QObject::connect(ui_theme_combobox, SIGNAL(currentIndexChanged(int)), this,
 | 
			
		||||
@ -902,7 +911,131 @@ AOOptionsDialog::AOOptionsDialog(QWidget *parent, AOApplication *p_ao_app)
 | 
			
		||||
 | 
			
		||||
  ui_casing_layout->setWidget(row, QFormLayout::FieldRole, ui_log_cb);
 | 
			
		||||
 | 
			
		||||
  // Assets tab
 | 
			
		||||
  ui_assets_tab = new QWidget(this);
 | 
			
		||||
  ui_assets_tab_layout = new QVBoxLayout(ui_assets_tab);
 | 
			
		||||
  ui_assets_tab->setLayout(ui_assets_tab_layout);
 | 
			
		||||
  ui_settings_tabs->addTab(ui_assets_tab, tr("Assets"));
 | 
			
		||||
 | 
			
		||||
  ui_asset_lbl = new QLabel(ui_assets_tab);
 | 
			
		||||
  ui_asset_lbl->setText(
 | 
			
		||||
        tr("Add or remove base folders for use by assets. "
 | 
			
		||||
           "Base folders will be searched in the order provided."));
 | 
			
		||||
  ui_asset_lbl->setWordWrap(true);
 | 
			
		||||
  ui_assets_tab_layout->addWidget(ui_asset_lbl);
 | 
			
		||||
 | 
			
		||||
  ui_mount_list = new QListWidget(ui_assets_tab);
 | 
			
		||||
  ui_assets_tab_layout->addWidget(ui_mount_list);
 | 
			
		||||
 | 
			
		||||
  ui_mount_buttons_layout = new QGridLayout(ui_assets_tab);
 | 
			
		||||
  ui_assets_tab_layout->addLayout(ui_mount_buttons_layout);
 | 
			
		||||
 | 
			
		||||
  QSizePolicy stretch_btns(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
 | 
			
		||||
  stretch_btns.setHorizontalStretch(4);
 | 
			
		||||
 | 
			
		||||
  ui_mount_add = new QPushButton(tr("Add…"), ui_assets_tab);
 | 
			
		||||
  ui_mount_add->setSizePolicy(stretch_btns);
 | 
			
		||||
  ui_mount_buttons_layout->addWidget(ui_mount_add, 0, 0, 1, 1);
 | 
			
		||||
  connect(ui_mount_add, &QPushButton::clicked, this, [this] {
 | 
			
		||||
    QString dir = QFileDialog::getExistingDirectory(this, tr("Select a base folder"),
 | 
			
		||||
                                                    QApplication::applicationDirPath(),
 | 
			
		||||
                                                    QFileDialog::ShowDirsOnly);
 | 
			
		||||
    if (dir.isEmpty())
 | 
			
		||||
      return;
 | 
			
		||||
    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);
 | 
			
		||||
  ui_mount_remove->setSizePolicy(stretch_btns);
 | 
			
		||||
  ui_mount_remove->setEnabled(false);
 | 
			
		||||
  ui_mount_buttons_layout->addWidget(ui_mount_remove, 0, 1, 1, 1);
 | 
			
		||||
  connect(ui_mount_remove, &QPushButton::clicked, this, [=] {
 | 
			
		||||
    auto selected = ui_mount_list->selectedItems();
 | 
			
		||||
    if (selected.isEmpty())
 | 
			
		||||
      return;
 | 
			
		||||
    delete selected[0];
 | 
			
		||||
    emit ui_mount_list->itemSelectionChanged();
 | 
			
		||||
    asset_cache_dirty = true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  auto *mount_buttons_spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding,
 | 
			
		||||
                                               QSizePolicy::Minimum);
 | 
			
		||||
  ui_mount_buttons_layout->addItem(mount_buttons_spacer, 0, 2, 1, 1);
 | 
			
		||||
 | 
			
		||||
  ui_mount_up = new QPushButton(tr("↑"), ui_assets_tab);
 | 
			
		||||
  ui_mount_up->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
 | 
			
		||||
  ui_mount_up->setMaximumWidth(40);
 | 
			
		||||
  ui_mount_up->setEnabled(false);
 | 
			
		||||
  ui_mount_buttons_layout->addWidget(ui_mount_up, 0, 3, 1, 1);
 | 
			
		||||
  connect(ui_mount_up, &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 = 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);
 | 
			
		||||
  ui_mount_down->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
 | 
			
		||||
  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();
 | 
			
		||||
 | 
			
		||||
  // When we're done, we should continue the updates!
 | 
			
		||||
  setUpdatesEnabled(true);
 | 
			
		||||
}
 | 
			
		||||
@ -976,6 +1109,12 @@ void AOOptionsDialog::update_values() {
 | 
			
		||||
  ui_blips_volume_spinbox->setValue(ao_app->get_default_blip());
 | 
			
		||||
  ui_bliprate_spinbox->setValue(ao_app->read_blip_rate());
 | 
			
		||||
  ui_default_showname_textbox->setText(ao_app->get_default_showname());
 | 
			
		||||
 | 
			
		||||
  auto *defaultMount = new QListWidgetItem(tr("%1 (default)")
 | 
			
		||||
                                           .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()
 | 
			
		||||
@ -1050,9 +1189,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.
 | 
			
		||||
 | 
			
		||||
@ -164,8 +164,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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -612,7 +612,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();
 | 
			
		||||
@ -1222,6 +1222,12 @@ void Courtroom::set_stylesheet(QWidget *widget)
 | 
			
		||||
void Courtroom::set_stylesheets()
 | 
			
		||||
{
 | 
			
		||||
  set_stylesheet(this);
 | 
			
		||||
  this->setStyleSheet(
 | 
			
		||||
    "QFrame { background-color:transparent; } "
 | 
			
		||||
    "QAbstractItemView { background-color: transparent; color: black; } "
 | 
			
		||||
    "QLineEdit { background-color:transparent; }"
 | 
			
		||||
    + this->styleSheet()
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Courtroom::set_window_title(QString p_title)
 | 
			
		||||
@ -1492,11 +1498,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"
 | 
			
		||||
@ -1631,7 +1637,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);
 | 
			
		||||
@ -4431,8 +4437,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) {
 | 
			
		||||
@ -4488,7 +4495,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()) !=
 | 
			
		||||
@ -4499,7 +4507,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));
 | 
			
		||||
@ -4576,7 +4584,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
 | 
			
		||||
@ -4589,10 +4598,10 @@ 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";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  QDesktopServices::openUrl(QUrl::fromLocalFile(p_path));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4625,12 +4634,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);
 | 
			
		||||
@ -4664,9 +4672,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;
 | 
			
		||||
    }
 | 
			
		||||
@ -4676,7 +4684,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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
#include <QCoreApplication>
 | 
			
		||||
#include <QElapsedTimer>
 | 
			
		||||
#include <QMessageBox>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -235,6 +235,12 @@ void Lobby::set_stylesheet(QWidget *widget)
 | 
			
		||||
void Lobby::set_stylesheets()
 | 
			
		||||
{
 | 
			
		||||
  set_stylesheet(this);
 | 
			
		||||
  this->setStyleSheet(
 | 
			
		||||
    "QFrame { background-color:transparent; } "
 | 
			
		||||
    "QAbstractItemView { background-color: transparent; color: black; } "
 | 
			
		||||
    "QLineEdit { background-color:transparent; }"
 | 
			
		||||
    + this->styleSheet()
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Lobby::set_font(QWidget *widget, QString p_identifier)
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#include <QDir>
 | 
			
		||||
#include <QRegExp>
 | 
			
		||||
#include <QStandardPaths>
 | 
			
		||||
#include <QStringBuilder>
 | 
			
		||||
 | 
			
		||||
#ifdef BASE_OVERRIDE
 | 
			
		||||
#include "base_override.h"
 | 
			
		||||
@ -39,72 +40,57 @@ QString AOApplication::get_base_path()
 | 
			
		||||
  return base_path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString AOApplication::get_data_path() { return get_base_path() + "data/"; }
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    QVector<VPath> pathlist;
 | 
			
		||||
    if (p_character != "")
 | 
			
		||||
      pathlist += get_character_path(p_character, p_element); // Character folder
 | 
			
		||||
    if (p_misc != "" && p_theme != "" && p_subtheme != "")
 | 
			
		||||
@ -119,7 +105,7 @@ QStringList AOApplication::get_asset_paths(QString p_element, QString p_theme, Q
 | 
			
		||||
      pathlist += get_theme_path(p_element, p_theme); // Theme path
 | 
			
		||||
    if (p_default_theme != "")
 | 
			
		||||
      pathlist += get_theme_path(p_element, p_default_theme); // Default theme path
 | 
			
		||||
    pathlist += p_element; // The path by itself
 | 
			
		||||
    pathlist += VPath(p_element); // The path by itself
 | 
			
		||||
    if (p_placeholder != "" && p_theme != "")
 | 
			
		||||
      pathlist += get_theme_path(p_placeholder, p_theme); // Placeholder path
 | 
			
		||||
    if (p_placeholder != "" && p_default_theme != "")
 | 
			
		||||
@ -127,52 +113,48 @@ 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 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;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString AOApplication::get_sfx_path(QStringList 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_image_suffix(p, static_image);
 | 
			
		||||
      if (!path.isEmpty()) {
 | 
			
		||||
          return path;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  return path;
 | 
			
		||||
  return QString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString AOApplication::get_sfx_path(QVector<VPath> pathlist)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
    const auto paths = get_asset_paths(p_config, p_theme, p_subtheme, p_default_theme, p_misc);
 | 
			
		||||
    for (const VPath &p : paths) {
 | 
			
		||||
        path = get_real_path(p);
 | 
			
		||||
        if (!path.isEmpty()) {
 | 
			
		||||
            QSettings settings(path, QSettings::IniFormat);
 | 
			
		||||
            settings.setIniCodec("UTF-8");
 | 
			
		||||
            QVariant value = settings.value(p_identifier);
 | 
			
		||||
            if (value.type() == QVariant::StringList) {
 | 
			
		||||
@ -193,25 +175,22 @@ 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
 | 
			
		||||
#ifdef CASE_SENSITIVE_FILESYSTEM
 | 
			
		||||
  // first, check to see if it's actually there (also serves as base case for
 | 
			
		||||
  // recursion)
 | 
			
		||||
  QFileInfo file(p_file);
 | 
			
		||||
@ -219,6 +198,7 @@ QString AOApplication::get_case_sensitive_path(QString p_file)
 | 
			
		||||
  if (exists(p_file))
 | 
			
		||||
    return p_file;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  QString file_parent_dir = get_case_sensitive_path(file.absolutePath());
 | 
			
		||||
 | 
			
		||||
  // second, does it exist in the new parent dir?
 | 
			
		||||
@ -226,14 +206,20 @@ QString AOApplication::get_case_sensitive_path(QString p_file)
 | 
			
		||||
    return file_parent_dir + "/" + file_basename;
 | 
			
		||||
 | 
			
		||||
  // last resort, dirlist parent dir and find case insensitive match
 | 
			
		||||
  QRegExp file_rx =
 | 
			
		||||
      QRegExp(file_basename, Qt::CaseInsensitive, QRegExp::FixedString);
 | 
			
		||||
  QStringList files = QDir(file_parent_dir).entryList();
 | 
			
		||||
 | 
			
		||||
  int result = files.indexOf(file_rx);
 | 
			
		||||
  if (!dir_listing_exist_cache.contains(qHash(file_parent_dir))) {
 | 
			
		||||
    QStringList files = QDir(file_parent_dir).entryList();
 | 
			
		||||
    for (const QString &file : files) {
 | 
			
		||||
      dir_listing_cache.insert(qHash(file_parent_dir % QChar('/') % file.toLower()), file);
 | 
			
		||||
    }
 | 
			
		||||
    dir_listing_exist_cache.insert(qHash(file_parent_dir));
 | 
			
		||||
  }
 | 
			
		||||
  QString found_file = dir_listing_cache.value(
 | 
			
		||||
        qHash(file_parent_dir % QChar('/') % file_basename.toLower()));
 | 
			
		||||
 | 
			
		||||
  if (result != -1)
 | 
			
		||||
    return file_parent_dir + "/" + files.at(result);
 | 
			
		||||
  if (!found_file.isEmpty()) {
 | 
			
		||||
    return file_parent_dir + "/" + found_file;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // if nothing is found, let the caller handle the missing file
 | 
			
		||||
  return file_parent_dir + "/" + file_basename;
 | 
			
		||||
@ -241,3 +227,72 @@ 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(qHash(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);
 | 
			
		||||
    QString path = baseDir.absoluteFilePath(vpath.toQString());
 | 
			
		||||
    if (!path.startsWith(baseDir.absolutePath())) {
 | 
			
		||||
      qWarning() << "invalid path" << path << "(path is outside vfs)";
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    path = get_case_sensitive_path(path);
 | 
			
		||||
    if (exists(path)) {
 | 
			
		||||
      asset_lookup_cache.insert(qHash(vpath), path);
 | 
			
		||||
      return path;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // File or directory not found
 | 
			
		||||
  return QString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Special case of get_real_path where multiple suffixes need to be tried
 | 
			
		||||
// on each mount path.
 | 
			
		||||
QString AOApplication::get_real_suffixed_path(const VPath &vpath,
 | 
			
		||||
                                              const QStringList &suffixes) {
 | 
			
		||||
  // Try cache first
 | 
			
		||||
  QString phys_path = asset_lookup_cache.value(qHash(vpath));
 | 
			
		||||
  if (!phys_path.isEmpty() && exists(phys_path)) {
 | 
			
		||||
    return phys_path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Cache miss; try each suffix on all known mount paths
 | 
			
		||||
  QStringList bases = get_mount_paths();
 | 
			
		||||
  bases.push_front(get_base_path());
 | 
			
		||||
 | 
			
		||||
  for (const QString &base : bases) {
 | 
			
		||||
    for (const QString &suffix : suffixes) {
 | 
			
		||||
      QDir baseDir(base);
 | 
			
		||||
      QString path = baseDir.absoluteFilePath(vpath.toQString() + suffix);
 | 
			
		||||
      if (!path.startsWith(baseDir.absolutePath())) {
 | 
			
		||||
        qWarning() << "invalid path" << path << "(path is outside vfs)";
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      path = get_case_sensitive_path(path);
 | 
			
		||||
      if (exists(path)) {
 | 
			
		||||
        asset_lookup_cache.insert(qHash(vpath), path);
 | 
			
		||||
        return path;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // File or directory not found
 | 
			
		||||
  return QString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AOApplication::invalidate_lookup_cache() {
 | 
			
		||||
  asset_lookup_cache.clear();
 | 
			
		||||
  dir_listing_cache.clear();
 | 
			
		||||
  dir_listing_exist_cache.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -130,6 +130,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;
 | 
			
		||||
@ -279,6 +284,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)
 | 
			
		||||
{
 | 
			
		||||
@ -448,12 +459,14 @@ QString AOApplication::get_chat_markup(QString p_identifier, QString p_chat)
 | 
			
		||||
    return value.toUtf8();
 | 
			
		||||
 | 
			
		||||
  // Backwards ass compatibility
 | 
			
		||||
  QStringList backwards_paths{get_theme_path("misc/" + p_chat + "/config.ini"),
 | 
			
		||||
                    get_base_path() + "misc/" + p_chat +
 | 
			
		||||
                        "/config.ini",
 | 
			
		||||
                    get_theme_path("misc/default/config.ini"),
 | 
			
		||||
                    get_base_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"),
 | 
			
		||||
    get_theme_path("misc/default/config.ini"),
 | 
			
		||||
    VPath("misc/default/config.ini")
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  for (const VPath &p : backwards_paths) {
 | 
			
		||||
    QString value = read_design_ini(p_identifier, p);
 | 
			
		||||
    if (!value.isEmpty()) {
 | 
			
		||||
      return value.toUtf8();
 | 
			
		||||
@ -490,36 +503,21 @@ QString AOApplication::get_court_sfx(QString p_identifier, QString p_misc)
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString AOApplication::get_sfx_suffix(QString sound_to_check)
 | 
			
		||||
QString AOApplication::get_sfx_suffix(VPath 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";
 | 
			
		||||
  return get_real_suffixed_path(sound_to_check,
 | 
			
		||||
                                { "", ".opus", ".ogg", ".mp3", ".wav" });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString AOApplication::get_image_suffix(QString path_to_check, bool static_image)
 | 
			
		||||
QString AOApplication::get_image_suffix(VPath path_to_check, bool static_image)
 | 
			
		||||
{
 | 
			
		||||
  if (file_exists(path_to_check))
 | 
			
		||||
    return path_to_check;
 | 
			
		||||
  // A better method would to actually use AOImageReader and see if these images have more than 1 frame.
 | 
			
		||||
  // However, that might not be performant.
 | 
			
		||||
  QStringList suffixes { "" };
 | 
			
		||||
  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_real_suffixed_path(path_to_check, suffixes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns whatever is to the right of "search_line =" within target_tag and
 | 
			
		||||
@ -528,7 +526,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);
 | 
			
		||||
  settings.setIniCodec("UTF-8");
 | 
			
		||||
@ -540,7 +538,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);
 | 
			
		||||
@ -548,10 +546,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);
 | 
			
		||||
  settings.setIniCodec("UTF-8");
 | 
			
		||||
  if (!target_tag.isEmpty())
 | 
			
		||||
    settings.beginGroup(target_tag);
 | 
			
		||||
@ -1095,3 +1093,8 @@ QString AOApplication::get_default_scaling()
 | 
			
		||||
{
 | 
			
		||||
  return configini->value("default_scaling", "fast").value<QString>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QStringList AOApplication::get_mount_paths()
 | 
			
		||||
{
 | 
			
		||||
  return configini->value("mount_paths").value<QStringList>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user