Skip to content

Commit

Permalink
Merge pull request #761 from openstudiocoalition/262_263_handle_path_…
Browse files Browse the repository at this point in the history
…arguments

Fix #262 #263 - Handle Path Arguments (QFileDialog)
  • Loading branch information
jmarrec authored Nov 7, 2024
2 parents d78fe3a + 6027455 commit d279ff2
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 13 deletions.
31 changes: 31 additions & 0 deletions src/shared_gui_components/EditController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "EditView.hpp"
#include "OSViewSwitcher.hpp"
#include "WorkflowController.hpp"
#include "../model_editor/Utilities.hpp"

#include <openstudio/utilities/bcl/BCLMeasure.hpp>
#include <openstudio/utilities/core/Assert.hpp>
Expand Down Expand Up @@ -251,6 +252,22 @@ InputController::InputController(EditController* editController, measure::OSArgu
static_cast<void (InputController::*)(const QString&)>(&InputController::setValue));

inputView = stringInputView;
} else if (m_argument.type() == measure::OSArgumentType::Path) {
auto* pathInputView = new PathInputView(m_argument.extension(), m_argument.isRead());

pathInputView->setName(m_argument.displayName(), m_argument.units(), m_argument.description());

if (m_argument.hasValue()) {
pathInputView->lineEdit->setText(QString::fromStdString(m_argument.valueAsString()));
} else if (m_argument.hasDefaultValue()) {
pathInputView->lineEdit->setText(QString::fromStdString(m_argument.defaultValueAsString()));
}

connect(pathInputView, &PathInputView::selectedPathChanged, this,
static_cast<void (InputController::*)(const openstudio::path&)>(&InputController::setValue));
connect(pathInputView->lineEdit, &QLineEdit::textEdited, [this](const QString& v) { this->setValue(toPath(v)); });

inputView = pathInputView;
} else {
inputView = new InputView();
}
Expand Down Expand Up @@ -302,6 +319,20 @@ void InputController::setValueForIndex(int index) {
}
}

void InputController::setValue(const openstudio::path& p) {
if (isItOKToClearResults()) {
if (p.empty()) {
m_argument.clearValue();
} else {
m_argument.setValue(p);
}

m_editController->measureStepItem()->setArgument(m_argument);

inputView->setIncomplete(isArgumentIncomplete());
}
}

bool InputController::isArgumentIncomplete() const {
bool result = false;
std::vector<measure::OSArgument> incompleteArguments = m_editController->measureStepItem()->incompleteArguments();
Expand Down
2 changes: 2 additions & 0 deletions src/shared_gui_components/EditController.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ class InputController : public QObject

void setValue(bool value);

void setValue(const openstudio::path& p);

void setValueForIndex(int index);

private:
Expand Down
82 changes: 80 additions & 2 deletions src/shared_gui_components/EditView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
***********************************************************************************************************************/

#include "EditView.hpp"
#include "../model_editor/Utilities.hpp"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
Expand All @@ -18,6 +20,8 @@
#include <QCheckBox>
#include <QWheelEvent>
#include <QApplication>
#include <QPushButton>
#include <QFileDialog>

#include <openstudio/utilities/core/Assert.hpp>

Expand Down Expand Up @@ -369,8 +373,6 @@ InputCheckBox::InputCheckBox() : QAbstractButton() {
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}

InputCheckBox::~InputCheckBox() = default;

void InputCheckBox::setText(const QString& text) {
m_label->setText(text);

Expand Down Expand Up @@ -400,4 +402,80 @@ void InputCheckBox::setIncomplete(bool incomplete) {
}
}

PathInputView::PathInputView(const std::string& extension, bool isRead)
: InputView(), lineEdit(new QLineEdit()), nameLabel(new QLabel()), m_isRead(isRead) {
auto* vLayout = new QVBoxLayout();
vLayout->setContentsMargins(0, 0, 0, 0);
vLayout->setSpacing(5);
setLayout(vLayout);

nameLabel->setOpenExternalLinks(true);
nameLabel->setWordWrap(true);
vLayout->addWidget(nameLabel);

auto* hLayout = new QHBoxLayout();
hLayout->addWidget(lineEdit);

selectPathButton = new QPushButton("...");
selectPathButton->setFlat(true);
selectPathButton->setFixedSize(30, 20);
selectPathButton->setObjectName("StandardGrayButton");

connect(selectPathButton, &QPushButton::clicked, this, &PathInputView::onSelectPathButtonClicked);
hLayout->addWidget(selectPathButton);

vLayout->addLayout(hLayout);

// TODO: sanitize the input?
m_extension = toQString(extension);
}

void PathInputView::setName(const std::string& name, const boost::optional<std::string>& units, const boost::optional<std::string>& description) {
QString text;
text += QString::fromStdString(name);
if (units) {
text += QString::fromStdString(" (" + units.get() + ")");
}
if (description) {
text += QString::fromStdString("<div style=\"font-size:small;margin-top:2px;\">" + description.get() + "</div>");
}

nameLabel->setText(text);
}

void PathInputView::setIncomplete(bool incomplete) {
if (incomplete) {
nameLabel->setStyleSheet("QLabel { color: #DD0A05;}");
} else {
nameLabel->setStyleSheet("QLabel { color: black;}");
}
}

void PathInputView::setDisplayValue(const QVariant& value) {
lineEdit->setText(value.toString());
}

void PathInputView::onSelectPathButtonClicked() {
QString lastPath = lineEdit->text();

QString selectedPath;

if (m_extension.isEmpty()) {
// Assume this is a directory
selectedPath =
QFileDialog::getExistingDirectory(nullptr, tr("Open Directory"), lastPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
} else {
if (m_isRead) {
selectedPath = QFileDialog::getOpenFileName(nullptr, tr("Open Read File"), lastPath, m_extension);
} else {
selectedPath = QFileDialog::getSaveFileName(nullptr, tr("Select Save File"), lastPath, m_extension);
}
}

if (!selectedPath.isEmpty()) {
lineEdit->setText(selectedPath); // QFileInfo(selectedPath).absoluteFilePath()
emit selectedPathChanged(toPath(selectedPath));
}
}

} // namespace openstudio
51 changes: 41 additions & 10 deletions src/shared_gui_components/EditView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
#ifndef SHAREDGUICOMPONENTS_EDITVIEW_HPP
#define SHAREDGUICOMPONENTS_EDITVIEW_HPP

#include <QWidget>
#include <QComboBox>
#include <QAbstractButton>
#include <QComboBox>
#include <QLabel>
#include <QWidget>

#include <boost/optional.hpp>
#include <openstudio/utilities/core/Filesystem.hpp>

class QLineEdit;
class QPushButton;
class QTextEdit;
class QVBoxLayout;

Expand All @@ -27,7 +29,7 @@ class EditNullView : public QWidget

public:
explicit EditNullView(const QString& text = "Select a Measure to Edit");
virtual ~EditNullView() {}
virtual ~EditNullView() = default;

protected:
void paintEvent(QPaintEvent*) override;
Expand All @@ -39,7 +41,7 @@ class EditRubyMeasureView : public QWidget

public:
explicit EditRubyMeasureView(bool applyMeasureNow);
virtual ~EditRubyMeasureView() {}
virtual ~EditRubyMeasureView() = default;

QLineEdit* nameLineEdit;

Expand Down Expand Up @@ -77,7 +79,7 @@ class DoubleInputView : public InputView

public:
DoubleInputView();
virtual ~DoubleInputView() {}
virtual ~DoubleInputView() = default;

QLineEdit* lineEdit;

Expand All @@ -97,7 +99,7 @@ class ChoiceInputView : public InputView

public:
ChoiceInputView();
virtual ~ChoiceInputView() {}
virtual ~ChoiceInputView() = default;

QComboBox* comboBox;

Expand All @@ -117,7 +119,7 @@ class BoolInputView : public InputView

public:
BoolInputView();
virtual ~BoolInputView() {}
virtual ~BoolInputView() = default;

InputCheckBox* checkBox;

Expand All @@ -134,7 +136,7 @@ class IntegerInputView : public InputView

public:
IntegerInputView();
virtual ~IntegerInputView() {}
virtual ~IntegerInputView() = default;

QLineEdit* lineEdit;

Expand All @@ -154,7 +156,7 @@ class StringInputView : public InputView

public:
StringInputView();
virtual ~StringInputView() {}
virtual ~StringInputView() = default;

QLineEdit* lineEdit;

Expand Down Expand Up @@ -183,7 +185,7 @@ class InputCheckBox : public QAbstractButton
public:
InputCheckBox();

virtual ~InputCheckBox();
virtual ~InputCheckBox() = default;

void setText(const QString& text);

Expand All @@ -196,6 +198,35 @@ class InputCheckBox : public QAbstractButton
QLabel* m_label;
};

class PathInputView : public InputView
{
Q_OBJECT

public:
PathInputView(const std::string& extension, bool isRead);
virtual ~PathInputView() = default;

QLineEdit* lineEdit;
QPushButton* selectPathButton;

void setName(const std::string& name, const boost::optional<std::string>& units, const boost::optional<std::string>& description);

void setIncomplete(bool incomplete) override;

void setDisplayValue(const QVariant& value) override;

signals:
void selectedPathChanged(const openstudio::path& p);

private slots:
void onSelectPathButtonClicked();

private:
QLabel* nameLabel;
QString m_extension;
bool m_isRead;
};

} // namespace openstudio

#endif // SHAREDGUICOMPONENTS_EDITVIEW_HPP
4 changes: 3 additions & 1 deletion src/shared_gui_components/MeasureManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,10 @@ boost::optional<measure::OSArgument> MeasureManager::getArgument(const measure::

} else if (type.value() == measure::OSArgumentType::Path) {

// TODO: aside from the fact that these arguments are weird / incorrectly named, neither the BCL-gem schema nor OS SDK actually handle them so
// they are not even inside the measure.xml
bool isRead = argument.get("is_read", Json::Value(false)).asBool();
std::string extension = argument.get("extension", Json::Value("*")).asString();
std::string extension = argument.get("extension", Json::Value("All files (*)")).asString();

result = measure::OSArgument::makePathArgument(name, isRead, extension, required, modelDependent);

Expand Down
2 changes: 2 additions & 0 deletions src/shared_gui_components/WorkflowController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ void MeasureStepItem::setArgument(const measure::OSArgument& argument) {
m_step.setArgument(argument.name(), argument.valueAsDouble());
} else if (argument.type() == measure::OSArgumentType::Integer) {
m_step.setArgument(argument.name(), argument.valueAsInteger());
} else if (argument.type() == measure::OSArgumentType::Path) {
m_step.setArgument(argument.name(), openstudio::toString(argument.valueAsPath()));
} else {
m_step.setArgument(argument.name(), argument.valueAsString());
}
Expand Down

0 comments on commit d279ff2

Please sign in to comment.