Merge pull request #1454 from aws-lumberyard-dev/LYN-3619

New level dialog has no way to select a different folder
main
sphrose 5 years ago
parent b88d87a590
commit ef3e31c740

@ -17,7 +17,10 @@
// Qt // Qt
#include <QtWidgets/QPushButton> #include <QtWidgets/QPushButton>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer> #include <QTimer>
#include <QToolButton>
// Editor // Editor
#include "NewTerrainDialog.h" #include "NewTerrainDialog.h"
@ -30,11 +33,33 @@ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
// Folder in which levels are stored // Folder in which levels are stored
static const char kNewLevelDialog_LevelsFolder[] = "Levels"; static const char kNewLevelDialog_LevelsFolder[] = "Levels";
class LevelFolderValidator : public QValidator
{
public:
LevelFolderValidator(QObject* parent)
: QValidator(parent)
{
m_parentDialog = qobject_cast<CNewLevelDialog*>(parent);
}
QValidator::State validate([[maybe_unused]] QString& input, [[maybe_unused]] int& pos) const override
{
if (m_parentDialog->ValidateLevel())
{
return QValidator::Acceptable;
}
return QValidator::Intermediate;
}
private:
CNewLevelDialog* m_parentDialog;
};
// CNewLevelDialog dialog // CNewLevelDialog dialog
CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/) CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/)
: QDialog(pParent) : QDialog(pParent)
, m_ilevelFolders(0)
, m_bUpdate(false) , m_bUpdate(false)
, ui(new Ui::CNewLevelDialog) , ui(new Ui::CNewLevelDialog)
, m_initialized(false) , m_initialized(false)
@ -43,46 +68,70 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=NULL*/)
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("New Level")); setWindowTitle(tr("New Level"));
setMaximumSize(QSize(320, 280)); setMaximumSize(QSize(430, 180));
adjustSize(); adjustSize();
// Default level folder is root (Levels/)
m_ilevelFolders = 0;
m_bIsResize = false; m_bIsResize = false;
ui->TITLE->setText(tr("Assign a name and location to the new level."));
ui->STATIC1->setText(tr("Location:"));
ui->STATIC2->setText(tr("Name:"));
// Level name only supports ASCII characters // Level name only supports ASCII characters
QRegExp rx("[_a-zA-Z0-9-]+"); QRegExp rx("[_a-zA-Z0-9-]+");
QValidator* validator = new QRegExpValidator(rx, this); QValidator* validator = new QRegExpValidator(rx, this);
ui->LEVEL->setValidator(validator); ui->LEVEL->setValidator(validator);
connect(ui->LEVEL_FOLDERS, SIGNAL(activated(int)), this, SLOT(OnCbnSelendokLevelFolders())); validator = new LevelFolderValidator(this);
ui->LEVEL_FOLDERS->lineEdit()->setValidator(validator);
ui->LEVEL_FOLDERS->setErrorToolTip(
QString("The location must be a folder underneath the current project's %1 folder. (%2)")
.arg(kNewLevelDialog_LevelsFolder)
.arg(GetLevelsFolder()));
ui->LEVEL_FOLDERS->setClearButtonEnabled(true);
QToolButton* clearButton = AzQtComponents::LineEdit::getClearButton(ui->LEVEL_FOLDERS->lineEdit());
assert(clearButton);
connect(clearButton, &QToolButton::clicked, this, &CNewLevelDialog::OnClearButtonClicked);
connect(ui->LEVEL_FOLDERS->lineEdit(), &QLineEdit::textEdited, this, &CNewLevelDialog::OnLevelNameChange);
connect(ui->LEVEL_FOLDERS, &AzQtComponents::BrowseEdit::attachedButtonTriggered, this, &CNewLevelDialog::PopupAssetPicker);
connect(ui->LEVEL, &QLineEdit::textChanged, this, &CNewLevelDialog::OnLevelNameChange); connect(ui->LEVEL, &QLineEdit::textChanged, this, &CNewLevelDialog::OnLevelNameChange);
m_levelFolders = GetLevelsFolder();
m_level = "";
// First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which // First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which
// widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last. // widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last.
// Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system
// is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus(). // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus().
QTimer::singleShot(0, ui->LEVEL, SLOT(setFocus())); QTimer::singleShot(0, ui->LEVEL, SLOT(OnStartup()));
ReloadLevelFolder();
} }
CNewLevelDialog::~CNewLevelDialog() CNewLevelDialog::~CNewLevelDialog()
{ {
} }
void CNewLevelDialog::OnStartup()
{
UpdateData(false);
setFocus();
}
void CNewLevelDialog::UpdateData(bool fromUi) void CNewLevelDialog::UpdateData(bool fromUi)
{ {
if (fromUi) if (fromUi)
{ {
m_level = ui->LEVEL->text(); m_level = ui->LEVEL->text();
m_levelFolders = ui->LEVEL_FOLDERS->currentText(); m_levelFolders = ui->LEVEL_FOLDERS->text();
m_ilevelFolders = ui->LEVEL_FOLDERS->currentIndex();
} }
else else
{ {
ui->LEVEL->setText(m_level); ui->LEVEL->setText(m_level);
ui->LEVEL_FOLDERS->setCurrentText(m_levelFolders); ui->LEVEL_FOLDERS->lineEdit()->setText(m_levelFolders);
ui->LEVEL_FOLDERS->setCurrentIndex(m_ilevelFolders);
} }
} }
@ -90,7 +139,7 @@ void CNewLevelDialog::UpdateData(bool fromUi)
void CNewLevelDialog::OnInitDialog() void CNewLevelDialog::OnInitDialog()
{ {
ReloadLevelFolders(); ReloadLevelFolder();
// Disable OK until some text is entered // Disable OK until some text is entered
if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok))
@ -104,28 +153,19 @@ void CNewLevelDialog::OnInitDialog()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void CNewLevelDialog::ReloadLevelFolders() void CNewLevelDialog::ReloadLevelFolder()
{ {
QString levelsFolder = QString(Path::GetEditingGameDataFolder().c_str()) + "/" + kNewLevelDialog_LevelsFolder;
m_itemFolders.clear(); m_itemFolders.clear();
ui->LEVEL_FOLDERS->clear(); ui->LEVEL_FOLDERS->lineEdit()->clear();
ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/'); ui->LEVEL_FOLDERS->setText(QString(kNewLevelDialog_LevelsFolder) + '/');
ReloadLevelFoldersRec(levelsFolder);
} }
////////////////////////////////////////////////////////////////////////// QString CNewLevelDialog::GetLevelsFolder() const
void CNewLevelDialog::ReloadLevelFoldersRec(const QString& currentFolder)
{ {
QDir dir(currentFolder); QDir projectDir = QDir(Path::GetEditingGameDataFolder().c_str());
QDir projectLevelsDir = QDir(QStringLiteral("%1/%2").arg(projectDir.absolutePath()).arg(kNewLevelDialog_LevelsFolder));
QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach(const QFileInfo &fi, infoList) return projectLevelsDir.absolutePath();
{
m_itemFolders.push_back(fi.baseName());
ui->LEVEL_FOLDERS->addItem(QString(kNewLevelDialog_LevelsFolder) + '/' + fi.baseName());
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -133,26 +173,47 @@ QString CNewLevelDialog::GetLevel() const
{ {
QString output = m_level; QString output = m_level;
if (m_itemFolders.size() > 0 && m_ilevelFolders > 0) QDir projectLevelsDir = QDir(GetLevelsFolder());
if (!m_levelFolders.isEmpty())
{ {
output = m_itemFolders[m_ilevelFolders - 1] + "/" + m_level; output = m_levelFolders + "/" + m_level;
} }
return output; QString relativePath = projectLevelsDir.relativeFilePath(output);
return relativePath;
} }
////////////////////////////////////////////////////////////////////////// bool CNewLevelDialog::ValidateLevel()
void CNewLevelDialog::OnCbnSelendokLevelFolders() {
// Check that the selected folder is in or below the project/LEVELS folder.
QDir projectLevelsDir = QDir(GetLevelsFolder());
QString selectedFolder = ui->LEVEL_FOLDERS->text();
QString absolutePath = QDir::cleanPath(projectLevelsDir.absoluteFilePath(selectedFolder));
QString relativePath = projectLevelsDir.relativeFilePath(absolutePath);
// Prevent saving to a different drive.
if (projectLevelsDir.absolutePath()[0] != absolutePath[0])
{
return false;
}
if (relativePath.startsWith(".."))
{ {
UpdateData(); return false;
}
return true;
} }
void CNewLevelDialog::OnLevelNameChange() void CNewLevelDialog::OnLevelNameChange()
{ {
m_level = ui->LEVEL->text(); UpdateData(true);
// QRegExpValidator means the string will always be valid as long as it's not empty: // QRegExpValidator means the string will always be valid as long as it's not empty:
const bool valid = !m_level.isEmpty(); const bool valid = !m_level.isEmpty() && ValidateLevel();
// Use the validity to dynamically change the Ok button's enabled state // Use the validity to dynamically change the Ok button's enabled state
if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok)) if (QPushButton* button = ui->buttonBox->button(QDialogButtonBox::Ok))
@ -161,6 +222,24 @@ void CNewLevelDialog::OnLevelNameChange()
} }
} }
void CNewLevelDialog::OnClearButtonClicked()
{
ui->LEVEL_FOLDERS->lineEdit()->setText(GetLevelsFolder());
UpdateData(true);
}
void CNewLevelDialog::PopupAssetPicker()
{
QString newPath = QFileDialog::getExistingDirectory(nullptr, QObject::tr("Choose Destination Folder"), GetLevelsFolder());
if (!newPath.isEmpty())
{
ui->LEVEL_FOLDERS->setText(newPath);
OnLevelNameChange();
}
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void CNewLevelDialog::IsResize(bool bIsResize) void CNewLevelDialog::IsResize(bool bIsResize)
{ {

@ -34,6 +34,7 @@
#include <vector> #include <vector>
#include <QAbstractButton>
#include <QDialog> #include <QDialog>
#endif #endif
@ -50,28 +51,29 @@ public:
CNewLevelDialog(QWidget* pParent = nullptr); // standard constructor CNewLevelDialog(QWidget* pParent = nullptr); // standard constructor
~CNewLevelDialog(); ~CNewLevelDialog();
QString GetLevel() const; QString GetLevel() const;
void IsResize(bool bIsResize); void IsResize(bool bIsResize);
bool ValidateLevel();
protected: protected:
void UpdateData(bool fromUi = true); void UpdateData(bool fromUi = true);
void OnInitDialog(); void OnInitDialog();
void ReloadLevelFolders(); void ReloadLevelFolder();
void ReloadLevelFoldersRec(const QString& currentFolder);
void showEvent(QShowEvent* event); void showEvent(QShowEvent* event);
QString GetLevelsFolder() const;
protected slots: protected slots:
void OnCbnSelendokLevelFolders();
void OnLevelNameChange(); void OnLevelNameChange();
void OnClearButtonClicked();
void PopupAssetPicker();
void OnStartup();
public: public:
QString m_level; QString m_level;
QString m_levelFolders; QString m_levelFolders;
int m_ilevelFolders;
bool m_bIsResize; bool m_bIsResize;
bool m_bUpdate; bool m_bUpdate;

@ -6,30 +6,59 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>320</width> <width>430</width>
<height>280</height> <height>180</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item row="1" column="0" colspan="2"> <item>
<widget class="QGroupBox" name="PLACEHOLDER_TRN"> <spacer name="topVerticalSpacer">
<layout class="QFormLayout" name="formLayout_2"> <property name="orientation">
<property name="fieldGrowthPolicy"> <enum>Qt::Vertical</enum>
<enum>QFormLayout::AllNonFixedFieldsGrow</enum> </property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="TITLE">
<property name="text">
<string>Assign a name and location to the new level.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property> </property>
</layout>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="STATIC_GROUP1"> <widget class="QGroupBox" name="STATIC_GROUP1">
<property name="title"> <property name="styleSheet">
<string>Level</string> <string notr="true">border: 0px;</string>
</property> </property>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="STATIC2"> <widget class="QLabel" name="STATIC2">
<property name="text"> <property name="text">
<string>Name:</string> <string>Name</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -48,8 +77,14 @@
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="STATIC1"> <widget class="QLabel" name="STATIC1">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text"> <property name="text">
<string>Folder:</string> <string>Location</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -60,12 +95,28 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="LEVEL_FOLDERS"/> <widget class="AzQtComponents::BrowseEdit" name="LEVEL_FOLDERS" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2"> </layout>
</item>
<item>
<spacer name="verticalSpacer2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
@ -74,6 +125,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>AzQtComponents::BrowseEdit</class>
<extends>QWidget</extends>
<header location="global">AzQtComponents/Components/Widgets/BrowseEdit.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>

Loading…
Cancel
Save