summaryrefslogtreecommitdiff
path: root/src/modinfodialogtextfiles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modinfodialogtextfiles.cpp')
-rw-r--r--src/modinfodialogtextfiles.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp
new file mode 100644
index 00000000..7a09fa4e
--- /dev/null
+++ b/src/modinfodialogtextfiles.cpp
@@ -0,0 +1,252 @@
+#include "modinfodialogtextfiles.h"
+#include "ui_modinfodialog.h"
+#include "modinfodialog.h"
+#include "settings.h"
+#include <QMessageBox>
+
+class FileListModel : public QAbstractItemModel
+{
+public:
+ void clear()
+ {
+ m_files.clear();
+ endResetModel();
+ }
+
+ QModelIndex index(int row, int col, const QModelIndex& ={}) const override
+ {
+ return createIndex(row, col);
+ }
+
+ QModelIndex parent(const QModelIndex&) const override
+ {
+ return {};
+ }
+
+ int rowCount(const QModelIndex& ={}) const override
+ {
+ return static_cast<int>(m_files.size());
+ }
+
+ int columnCount(const QModelIndex& ={}) const override
+ {
+ return 1;
+ }
+
+ QVariant data(const QModelIndex& index, int role) const override
+ {
+ if (role == Qt::DisplayRole) {
+ const auto row = index.row();
+ if (row < 0) {
+ return {};
+ }
+
+ const auto i = static_cast<std::size_t>(row);
+ if (i >= m_files.size()) {
+ return {};
+ }
+
+ return m_files[i].text;
+ }
+
+ return {};
+ }
+
+ void add(const QString& rootPath, QString fullPath)
+ {
+ QString text = fullPath.mid(rootPath.length() + 1);
+ m_files.emplace_back(std::move(fullPath), std::move(text));
+ }
+
+ void finished()
+ {
+ std::sort(m_files.begin(), m_files.end(), [](const auto& a, const auto& b) {
+ return (naturalCompare(a.text, b.text) < 0);
+ });
+
+ endResetModel();
+ }
+
+ QString fullPath(const QModelIndex& index) const
+ {
+ const auto row = index.row();
+ if (row < 0) {
+ return {};
+ }
+
+ const auto i = static_cast<std::size_t>(row);
+ if (i >= m_files.size()) {
+ return {};
+ }
+
+ return m_files[i].fullPath;
+ }
+
+private:
+ struct File
+ {
+ QString fullPath;
+ QString text;
+
+ File(QString fp, QString t)
+ : fullPath(std::move(fp)), text(std::move(t))
+ {
+ }
+ };
+
+ std::deque<File> m_files;
+};
+
+
+GenericFilesTab::GenericFilesTab(
+ ModInfoDialogTabContext cx,
+ QListView* list, QSplitter* sp,
+ TextEditor* e, QLineEdit* filter) :
+ ModInfoDialogTab(std::move(cx)),
+ m_list(list), m_editor(e), m_splitter(sp), m_model(new FileListModel)
+{
+ m_list->setModel(m_model);
+ m_editor->setupToolbar();
+
+ m_splitter->setSizes({200, 1});
+ m_splitter->setStretchFactor(0, 0);
+ m_splitter->setStretchFactor(1, 1);
+
+ m_filter.setEdit(filter);
+ m_filter.setList(m_list);
+
+ QObject::connect(
+ m_list->selectionModel(), &QItemSelectionModel::currentRowChanged,
+ [&](auto current, auto previous){ onSelection(current, previous); });
+}
+
+void GenericFilesTab::clear()
+{
+ m_model->clear();
+ select({});
+ setHasData(false);
+}
+
+bool GenericFilesTab::canClose()
+{
+ if (!m_editor->dirty()) {
+ return true;
+ }
+
+ setFocus();
+
+ const int res = QMessageBox::question(
+ parentWidget(),
+ QObject::tr("Save changes?"),
+ QObject::tr("Save changes to \"%1\"?").arg(m_editor->filename()),
+ QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
+
+ if (res == QMessageBox::Cancel) {
+ return false;
+ }
+
+ if (res == QMessageBox::Yes) {
+ m_editor->save();
+ }
+
+ return true;
+}
+
+bool GenericFilesTab::feedFile(const QString& rootPath, const QString& fullPath)
+{
+ static constexpr const char* extensions[] = {
+ ".txt"
+ };
+
+ for (const auto* e : extensions) {
+ if (wantsFile(rootPath, fullPath)) {
+ m_model->add(rootPath, fullPath);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void GenericFilesTab::update()
+{
+ m_model->finished();
+ setHasData(m_model->rowCount() > 0);
+}
+
+void GenericFilesTab::saveState(Settings& s)
+{
+ saveWidgetState(s.directInterface(), m_splitter);
+}
+
+void GenericFilesTab::restoreState(const Settings& s)
+{
+ restoreWidgetState(s.directInterface(), m_splitter);
+}
+
+void GenericFilesTab::onSelection(
+ const QModelIndex& current, const QModelIndex& previous)
+{
+ if (!canClose()) {
+ m_list->selectionModel()->select(previous, QItemSelectionModel::Current);
+ return;
+ }
+
+ select(current);
+}
+
+void GenericFilesTab::select(const QModelIndex& index)
+{
+ if (!index.isValid()) {
+ m_editor->clear();
+ m_editor->setEnabled(false);
+ return;
+ }
+
+ m_editor->setEnabled(true);
+ m_editor->load(m_model->fullPath(m_filter.map(index)));
+}
+
+
+TextFilesTab::TextFilesTab(ModInfoDialogTabContext cx)
+ : GenericFilesTab(cx,
+ cx.ui->textFileList, cx.ui->tabTextSplitter,
+ cx.ui->textFileEditor, cx.ui->textFileFilter)
+{
+}
+
+bool TextFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const
+{
+ static const QString extensions[] = {".txt"};
+
+ for (const auto& e : extensions) {
+ if (fullPath.endsWith(e, Qt::CaseInsensitive)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+IniFilesTab::IniFilesTab(ModInfoDialogTabContext cx)
+ : GenericFilesTab(cx,
+ cx.ui->iniFileList, cx.ui->tabIniSplitter,
+ cx.ui->iniFileEditor, cx.ui->iniFileFilter)
+{
+}
+
+bool IniFilesTab::wantsFile(const QString& rootPath, const QString& fullPath) const
+{
+ static const QString extensions[] = {".ini", ".cfg"};
+ static const QString meta("meta.ini");
+
+ for (const auto& e : extensions) {
+ if (fullPath.endsWith(e, Qt::CaseInsensitive)) {
+ if (!fullPath.endsWith(meta)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}