Crossfire Server, Trunk
AssetOriginAndCreationDialog.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2022 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
14 #include "global.h"
15 
16 const char * const addTitles[] = {
17  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Quest creation"),
18  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Treasure creation"),
19  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Archetype creation"),
20 };
21 const char * const originTitles[] = {
22  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Quest file definition"),
23  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Treasure list file definition"),
24  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "Archetype file definition"),
25 };
26 const char * const names[] = {
27  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "quest"),
28  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "treasure"),
29  QT_TRANSLATE_NOOP("AssetOriginAndCreationDialog", "archetype"),
30 };
31 const char * const extensions[] = {
32  ".quests",
33  ".trs",
34  ".arc",
35 };
36 
37 // Whether this file is part of 'arch' (true) or 'maps' (false)
38 const bool isArch[] = {
39  false,
40  true,
41  true,
42 };
43 
45  const std::vector<std::string> &origins, const std::vector<std::string> &assets) : myType(type), myAssets(assets) {
46  setModal(true);
47  setWindowTitle(tr(mode == CreateAsset ? addTitles[type] : originTitles[type]));
48  QGridLayout *layout = new QGridLayout(this);
49 
50  myRootDirectory = QString("%1/%2/").arg(settings.datadir, isArch[type] ? "arch" : settings.mapdir);
51 
52  layout->addWidget(new QLabel(tr("Code:")), 1, 0);
53  layout->addWidget(myCode = new QLineEdit(this), 1, 1, 1, 2);
54  if (mode == DefineOrigin) {
55  myCode->setReadOnly(true);
56  myCode->setText(code);
57  }
58 
59  QRadioButton *existing = new QRadioButton(tr("Add to an existing %1 file:").arg(names[type]), this);
60  layout->addWidget(existing, 2, 0);
61  myExistingFile = new QComboBox(this);
62  for (const auto &origin : origins) {
63  myExistingFile->addItem(QString::fromStdString(origin));
64  }
65  layout->addWidget(myExistingFile, 2, 1, 1, 2);
66 
67  QRadioButton *nqf = new QRadioButton(tr("Create a new %1 file:").arg(names[type]), this);
68  layout->addWidget(nqf, 3, 0);
69  myNewFile = new QLineEdit(this);
70  layout->addWidget(myNewFile, 3, 1);
71  auto browse = new QPushButton(tr("Browse..."), this);
72  layout->addWidget(browse, 3, 2);
73  connect(browse, &QAbstractButton::clicked, [this] () {
74  QFileDialog dlg;
75  if (myNewFile->text().isEmpty()) {
76  dlg.setDirectory(myRootDirectory);
77  } else {
78  dlg.selectFile(myNewFile->text());
79  }
80  dlg.setNameFilter(tr("%1 file (*%2);;All files (*.*)").arg(names[myType], extensions[myType]));
81  dlg.setAcceptMode(QFileDialog::AcceptSave);
82  dlg.setFileMode(QFileDialog::AnyFile);
83  if (dlg.exec() == QDialog::Accepted) {
84  myNewFile->setText(dlg.selectedFiles()[0]);
85  }
86  });
87 
88  connect(existing, &QAbstractButton::clicked, [this, browse] {
89  myExistingFile->setEnabled(true);
90  myNewFile->setEnabled(false);
91  browse->setEnabled(false);
92  });
93  connect(nqf, &QAbstractButton::clicked, [this, browse] {
94  myExistingFile->setEnabled(false);
95  myNewFile->setEnabled(true);
96  browse->setEnabled(true);
97  if (myNewFile->text().isEmpty()) {
98  browse->click();
99  }
100  });
101  existing->click();
102 
103  auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
104  connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
105  connect(buttons, &QDialogButtonBox::accepted, [this] () { validate(); });
106  layout->addWidget(buttons, 4, 0, 1, 3);
107 }
108 
110  if (!myCode->isReadOnly()) {
111  if (myCode->text().isEmpty()) {
112  QMessageBox::critical(this, tr("Empty required field"), tr("Please enter a code."));
113  myCode->setFocus();
114  return;
115  }
116  if (std::find(myAssets.cbegin(), myAssets.cend(), myCode->text().toStdString()) != myAssets.cend()) {
117  QMessageBox::critical(this, tr("Code already exists"), tr("The code you entered matches an existing code."));
118  myCode->setFocus();
119  return;
120  }
121  }
122  if (myNewFile->isEnabled()) {
123  if (myNewFile->text().isEmpty()) {
124  QMessageBox::critical(this, tr("Empty file"), tr("Please enter a file to define the %1 into.").arg(names[myType]));
125  myNewFile->setFocus();
126  return;
127  }
128  if (!myNewFile->text().startsWith(myRootDirectory)) {
129  if (QMessageBox::question(this, tr("File warning"), tr("The file seems to be outside the root directory for this kind of assets (%1).\nThis means the asset will not be visible to the game.\nAre you sure you want to use this file?").arg(myRootDirectory)) != QMessageBox::Yes) {
130  myNewFile->setFocus();
131  return;
132  }
133  }
134  if (!myNewFile->text().endsWith(extensions[myType])) {
135  if (QMessageBox::question(this, tr("File warning"), tr("The file does not end with '%1'.\nThis means the asset will not be visible to the game.\nAre you sure you want to use this file?").arg(extensions[myType])) != QMessageBox::Yes) {
136  myNewFile->setFocus();
137  return;
138  }
139  }
140  }
141  accept();
142 }
extensions
const char *const extensions[]
Definition: AssetOriginAndCreationDialog.cpp:31
Settings::mapdir
const char * mapdir
Definition: global.h:251
global.h
settings
struct Settings settings
Definition: init.cpp:139
layout
Definition: main.cpp:84
isArch
const bool isArch[]
Definition: AssetOriginAndCreationDialog.cpp:38
AssetOriginAndCreationDialog::myAssets
std::vector< std::string > myAssets
Definition: AssetOriginAndCreationDialog.h:46
Settings::datadir
const char * datadir
Definition: global.h:248
AssetOriginAndCreationDialog::AssetOriginAndCreationDialog
AssetOriginAndCreationDialog(Type type, Mode mode, const QString &code, const std::vector< std::string > &origins, const std::vector< std::string > &assets)
Definition: AssetOriginAndCreationDialog.cpp:44
AssetOriginAndCreationDialog::DefineOrigin
@ DefineOrigin
Definition: AssetOriginAndCreationDialog.h:25
AssetOriginAndCreationDialog::CreateAsset
@ CreateAsset
Definition: AssetOriginAndCreationDialog.h:25
AssetOriginAndCreationDialog::myNewFile
QLineEdit * myNewFile
Definition: AssetOriginAndCreationDialog.h:45
addTitles
const char *const addTitles[]
Definition: AssetOriginAndCreationDialog.cpp:16
AssetOriginAndCreationDialog::Mode
Mode
Definition: AssetOriginAndCreationDialog.h:25
AssetOriginAndCreationDialog.h
AssetOriginAndCreationDialog::myCode
QLineEdit * myCode
Definition: AssetOriginAndCreationDialog.h:43
AssetOriginAndCreationDialog::validate
void validate()
Definition: AssetOriginAndCreationDialog.cpp:109
AssetOriginAndCreationDialog::myRootDirectory
QString myRootDirectory
Definition: AssetOriginAndCreationDialog.h:42
AssetOriginAndCreationDialog::Type
Type
Definition: AssetOriginAndCreationDialog.h:24
originTitles
const char *const originTitles[]
Definition: AssetOriginAndCreationDialog.cpp:21
names
const char *const names[]
Definition: AssetOriginAndCreationDialog.cpp:26
connect
Definition: connect.py:1
AssetOriginAndCreationDialog::myType
Type myType
Definition: AssetOriginAndCreationDialog.h:41
altar_valkyrie.accept
def accept(description)
Definition: altar_valkyrie.py:22
AssetOriginAndCreationDialog::code
QString code() const
Definition: AssetOriginAndCreationDialog.h:37
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
AssetOriginAndCreationDialog::myExistingFile
QComboBox * myExistingFile
Definition: AssetOriginAndCreationDialog.h:44