Skip to content

Commit

Permalink
Moved the context menu implementation back to PropertiesWidget
Browse files Browse the repository at this point in the history
This makes the property-specific actions like "Go to Object" and "Open
Containing Folder" available again, as well as the Cut, Copy and Paste
actions.

For now, the Custom Types Editor has no context menu anymore...

Property widgets are now removed before their property is deleted to
avoid a crash when right-clicking the AddValueProperty, since that
caused the focus to be lost and thus the removal of the property while
at the same time triggering a context menu for it.
  • Loading branch information
bjorn committed Dec 12, 2024
1 parent 73e6373 commit f6ed8d9
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 142 deletions.
75 changes: 60 additions & 15 deletions src/tiled/propertiesview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@

#include <QBoxLayout>
#include <QCheckBox>
#include <QFileInfo>
#include <QFontComboBox>
#include <QGridLayout>
#include <QGuiApplication>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMetaProperty>
#include <QPainter>
#include <QPointer>
Expand Down Expand Up @@ -136,6 +138,12 @@ QWidget *GroupProperty::createLabel(int level, QWidget *parent)
return label;
}

void GroupProperty::addContextMenuActions(QMenu *menu)
{
menu->addAction(tr("Expand All"), this, &GroupProperty::expandAll);
menu->addAction(tr("Collapse All"), this, &GroupProperty::collapseAll);
}

void GroupProperty::setExpanded(bool expanded)
{
if (m_expanded != expanded) {
Expand Down Expand Up @@ -224,6 +232,18 @@ QWidget *UrlProperty::createEditor(QWidget *parent)
return editor;
}

void UrlProperty::addContextMenuActions(QMenu *menu)
{
const QString localFile = value().toLocalFile();

if (!localFile.isEmpty()) {
Utils::addOpenContainingFolderAction(*menu, localFile);

if (QFileInfo { localFile }.isFile())
Utils::addOpenWithSystemEditorAction(*menu, localFile);
}
}

QWidget *IntProperty::createEditor(QWidget *parent)
{
auto widget = new QWidget(parent);
Expand Down Expand Up @@ -969,6 +989,12 @@ bool PropertiesView::focusProperty(Property *property, FocusTarget target)
return true;
}

Property *PropertiesView::focusedProperty() const
{
auto propertyWidget = qobject_cast<PropertyWidget *>(focusWidget());
return propertyWidget ? propertyWidget->property() : nullptr;
}

bool PropertiesView::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::Show) {
Expand All @@ -986,10 +1012,18 @@ bool PropertiesView::eventFilter(QObject *watched, QEvent *event)
return QScrollArea::eventFilter(watched, event);
}

void PropertiesView::mousePressEvent(QMouseEvent *event)
{
// If the view gets mouse press then no PropertyWidget was clicked
if (event->modifiers() == Qt::NoModifier)
setSelectedProperties({});

QScrollArea::mousePressEvent(event);
}

void PropertiesView::keyPressEvent(QKeyEvent *event)
{
auto propertyWidget = qobject_cast<PropertyWidget *>(focusWidget());
auto property = propertyWidget ? propertyWidget->property() : nullptr;
auto property = focusedProperty();
const auto key = event->key();
const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;

Expand Down Expand Up @@ -1092,10 +1126,7 @@ bool PropertiesView::focusNextPrevProperty(Property *property, bool next, bool s
return false;
}

/**
* Removes the given property from the editor. The property is not deleted.
*/
void PropertiesView::removeProperty(Property *property)
void PropertiesView::deletePropertyWidgets(Property *property)
{
auto it = m_propertyWidgets.constFind(property);
Q_ASSERT(it != m_propertyWidgets.constEnd());
Expand All @@ -1113,16 +1144,29 @@ void PropertiesView::removeProperty(Property *property)

rowWidget->deleteLater();

m_propertyWidgets.erase(it);
forgetProperty(property);

// This appears to be necessary to avoid flickering due to relayouting
// not being done before the next paint.
while (widget && widget->layout()) {
widget->layout()->activate();
widget = widget->parentWidget();
}
}

void PropertiesView::forgetProperty(Property *property)
{
m_propertyWidgets.remove(property);

if (property == m_selectionStart)
m_selectionStart = nullptr;

property->disconnect(this);

if (GroupProperty *groupProperty = qobject_cast<GroupProperty *>(property)) {
for (auto subProperty : groupProperty->subProperties())
forgetProperty(subProperty);
}
}

/**
Expand Down Expand Up @@ -1197,10 +1241,6 @@ PropertiesView::PropertyWidgets PropertiesView::createPropertyWidgets(Property *

const auto displayMode = property->displayMode();

connect(property, &Property::destroyed, this, [this](QObject *object) {
removeProperty(static_cast<Property *>(object));
});

if (displayMode == Property::DisplayMode::ChildrenOnly) {
QWidget *children;
if (auto groupProperty = qobject_cast<GroupProperty *>(property))
Expand Down Expand Up @@ -1240,7 +1280,7 @@ PropertiesView::PropertyWidgets PropertiesView::createPropertyWidgets(Property *

rowWidget->setSelectable(property->actions().testFlag(Property::Action::Select));

connect(rowWidget, &PropertyWidget::clicked, this, [=](Qt::KeyboardModifiers modifiers) {
connect(rowWidget, &PropertyWidget::mousePressed, this, [=](Qt::MouseButton button, Qt::KeyboardModifiers modifiers) {
if (modifiers & Qt::ShiftModifier) {
// Select range between m_selectionStart and clicked property
if (assignSelectedPropertiesRange(m_root, m_selectionStart, property))
Expand All @@ -1254,10 +1294,12 @@ PropertiesView::PropertyWidgets PropertiesView::createPropertyWidgets(Property *
}
} else {
// Select only the clicked property
if (property->actions().testFlag(Property::Action::Select))
setSelectedProperties({property});
else
if (property->actions().testFlag(Property::Action::Select)) {
if (button == Qt::LeftButton || !property->isSelected())
setSelectedProperties({property});
} else {
setSelectedProperties({});
}
}

m_selectionStart = property;
Expand Down Expand Up @@ -1371,6 +1413,9 @@ QWidget *PropertiesView::createChildrenWidget(GroupProperty *groupProperty,
createPropertyWidgets(property, children, level, layout, index);
});

connect(groupProperty, &GroupProperty::propertyRemoved,
this, &PropertiesView::deletePropertyWidgets);

return children;
}

Expand Down
27 changes: 25 additions & 2 deletions src/tiled/propertiesview.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class Property : public QObject

virtual QWidget *createLabel(int level, QWidget *parent);
virtual QWidget *createEditor(QWidget *parent) = 0;
virtual void addContextMenuActions(QMenu *) {}

signals:
void nameChanged(const QString &name);
Expand Down Expand Up @@ -165,6 +166,7 @@ class GroupProperty : public Property

QWidget *createLabel(int level, QWidget *parent) override;
QWidget *createEditor(QWidget */* parent */) override { return nullptr; }
void addContextMenuActions(QMenu *) override;

void setHeader(bool header) { m_header = header; }

Expand Down Expand Up @@ -194,10 +196,23 @@ class GroupProperty : public Property

void deleteProperty(Property *property)
{
m_subProperties.removeOne(property);
removeProperty(property);
delete property;
}

/**
* Removes the given property from this group. Ownership of the property
* is transferred to the caller.
*/
void removeProperty(Property *property)
{
if (!m_subProperties.removeOne(property))
return;

property->m_parent = nullptr;
emit propertyRemoved(property);
}

int indexOfProperty(Property *property) const
{
return m_subProperties.indexOf(property);
Expand All @@ -210,6 +225,7 @@ class GroupProperty : public Property
signals:
void expandedChanged(bool expanded);
void propertyAdded(int index, Property *property);
void propertyRemoved(Property *property);

private:
bool m_header = true;
Expand Down Expand Up @@ -270,9 +286,13 @@ struct MultilineStringProperty : StringProperty
struct UrlProperty : PropertyTemplate<QUrl>
{
using PropertyTemplate::PropertyTemplate;

QWidget *createEditor(QWidget *parent) override;
void addContextMenuActions(QMenu *) override;

void setFilter(const QString &filter) { m_filter = filter; }
void setIsDirectory(bool isDirectory) { m_isDirectory = isDirectory; }

private:
QString m_filter;
bool m_isDirectory = false;
Expand Down Expand Up @@ -528,19 +548,22 @@ class PropertiesView : public QScrollArea
};

bool focusProperty(Property *property, FocusTarget target = FocusEditor);
Property *focusedProperty() const;

signals:
void selectedPropertiesChanged();

protected:
bool eventFilter(QObject *watched, QEvent *event) override;

void mousePressEvent(QMouseEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;

private:
bool focusNextPrevProperty(Property *property, bool next, bool shiftPressed);

void removeProperty(Property *property);
void deletePropertyWidgets(Property *property);
void forgetProperty(Property *property);

QWidget *focusPropertyImpl(GroupProperty *group, Property *property, FocusTarget target);

Expand Down
Loading

0 comments on commit f6ed8d9

Please sign in to comment.