Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/usd/ui/layerEditor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ target_link_libraries(${PROJECT_NAME}
ghc_filesystem
)

# -----------------------------------------------------------------------------
# MSVC fix: avoid ambiguous qfloat16 arithmetic operators pulled by Qt headers
# Only needed for <= VS2017
# -----------------------------------------------------------------------------
if (MSVC AND MSVC_VERSION LESS 1920)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
QT_NO_FLOAT16_OPERATORS
)
endif()

# -----------------------------------------------------------------------------
# promoted headers
# -----------------------------------------------------------------------------
Expand Down
41 changes: 40 additions & 1 deletion lib/usd/ui/layerEditor/componentSaveDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
#include "generatedIconButton.h"
#include "qtUtils.h"

#include <mayaUsd/utils/util.h>
#include <mayaUsd/utils/utilComponentCreator.h>

#include <pxr/base/tf/diagnostic.h>

#include <maya/MGlobal.h>
#include <maya/MString.h>

Expand All @@ -42,6 +45,7 @@
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QStyle>
#include <QtWidgets/QTreeWidget>
#include <ghc/filesystem.hpp>

#include <string>

Expand Down Expand Up @@ -135,6 +139,10 @@ void ComponentSaveDialog::setupUI()

// Second row, first column: Name textbox
_nameEdit = new QLineEdit(this);

QValidator* compNameValidator = new TfValidIdentifierValidator(this);
_nameEdit->setValidator(compNameValidator);

contentLayout->addWidget(_nameEdit, 1, 0);

// Second row, second column: Location textbox
Expand Down Expand Up @@ -304,7 +312,38 @@ void ComponentSaveDialog::keyPressEvent(QKeyEvent* event)
QDialog::keyPressEvent(event);
}

void ComponentSaveDialog::onSaveStage() { accept(); }
void ComponentSaveDialog::onSaveStage()
{
// Block overwriting of components. The target folder must be empty.
// Otherwise, log an error and abort. In the future we will want to
// support overwriting components. This is not trivial as we need
// to be able to preflight all the file write operations, and only if
// we are certain everything will succeed, overwrite everything. We also
// need to handle about-to-be-overwritten, but already in memory layers,
// locked layers, and a possibly polluted folder if the old component had
// assets that would no longer be used by the new version.

ghc::filesystem::path location = { _locationEdit->text().toStdString() };
location.append(_nameEdit->text().toStdString());

if (ghc::filesystem::exists(location) && !ghc::filesystem::is_empty(location)) {

MObject obj;
UsdMayaUtil::GetMObjectByName(_proxyShapePath, obj);
const auto stageName = UsdMayaUtil::GetUniqueNameOfDagNode(obj);

PXR_NAMESPACE_USING_DIRECTIVE
TF_RUNTIME_ERROR(
"Cannot save %s with the given name since a non-empty folder with the same "
"name is already in that location. Use a unique name or save to a different location "
"and try the save again. Folder path:%s",
stageName.asChar(),
location.generic_string().c_str());
return;
}

accept();
}

void ComponentSaveDialog::onCancel() { reject(); }

Expand Down
42 changes: 30 additions & 12 deletions lib/usd/ui/layerEditor/layerEditorWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <mayaUsd/base/tokens.h>
#include <mayaUsd/utils/util.h>
#include <mayaUsd/utils/utilComponentCreator.h>

#include <maya/MGlobal.h>

Expand Down Expand Up @@ -328,18 +329,35 @@ void LayerEditorWidget::updateButtons()
if (_buttons._saveStageButton) {
_buttons._saveStageButton->setVisible(true);
}
const auto layers = _treeView->layerTreeModel()->getAllNeedsSavingLayers();
int count = static_cast<int>(layers.size());
for (auto layer : layers) {
// The system locked layers do not count towards saving.
if (layer->isSystemLocked()) {
count--;
}
// Neither does any anonymous layer whose parent is locked or system-locked.
// This is because saving an anonymous layer will cause
// the parent layer to re-path the sub layer with a file name.
if (layer->isAnonymous() && (layer->appearsLocked() || layer->appearsSystemLocked())) {
count--;

int count = 0;

// Special case for components created by the component creator. Non-local layers,
// non-active layers, and non-dirty but to be renamed layers, can be impacted when saving a
// component. Only the component creator knows how to save a component properly, we need to
// ask it what layers will be impacted.
if (MayaUsd::ComponentUtils::isAdskUsdComponent(
_sessionState.stageEntry()._proxyShapePath)) {
const auto layerIds = MayaUsd::ComponentUtils::getAdskUsdComponentLayersToSave(
_sessionState.stageEntry()._proxyShapePath);
count = static_cast<int>(layerIds.size());
}
// Normal case - layers visible in the layer editor.
else {
const auto layers = _treeView->layerTreeModel()->getAllNeedsSavingLayers();
count = static_cast<int>(layers.size());
for (auto layer : layers) {
// The system locked layers do not count towards saving.
if (layer->isSystemLocked()) {
count--;
}
// Neither does any anonymous layer whose parent is locked or system-locked.
// This is because saving an anonymous layer will cause
// the parent layer to re-path the sub layer with a file name.
if (layer->isAnonymous()
&& (layer->appearsLocked() || layer->appearsSystemLocked())) {
count--;
}
}
}
_buttons._dirtyCountBadge->updateCount(count);
Expand Down
20 changes: 20 additions & 0 deletions lib/usd/ui/layerEditor/qtUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//
#include "qtUtils.h"

#include <pxr/base/tf/stringUtils.h>

#include <QtGui/QIcon>
#include <QtGui/QPixmap>
#include <QtWidgets/QtWidgets>
Expand Down Expand Up @@ -145,4 +147,22 @@ QtDisableRepaintUpdates::~QtDisableRepaintUpdates()
}
}

TfValidIdentifierValidator::TfValidIdentifierValidator(QObject* parent)
: QValidator(parent)
{
}

QValidator::State TfValidIdentifierValidator::validate(QString& input, int& pos) const
{
std::string orig = input.toStdString();
std::string valid = pxr::TfMakeValidIdentifier(orig);
if (input.isEmpty()) {
return Intermediate; // Allow user to type
}
if (orig == valid && !valid.empty()) {
return Acceptable;
}
return Invalid;
}

} // namespace UsdLayerEditor
8 changes: 8 additions & 0 deletions lib/usd/ui/layerEditor/qtUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ class QtDisableRepaintUpdates
QWidget& _widget;
};

class TfValidIdentifierValidator : public QValidator
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to call it with Tf prefix? At first I thought it was a pixar class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Myeah the idea was to make it clear it's a "tf valid identifier"... "valid identifier" on its own could mean anything i guess

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just confusing because I expect classes and functions beginning with Tf, Sdf, Usd to be Pixar stuff, but not very important.

{
public:
explicit TfValidIdentifierValidator(QObject* parent = nullptr);

State validate(QString& input, int& pos) const override;
};

#ifdef Q_OS_DARWIN
const bool IS_MAC_OS = true;
#else
Expand Down