Gui: refactor link property editor

PropertyLinkItem now support all major types of link property.
PropertyLinkListItem is no longer necessary, but kept for backward
compatible, which is now identical to PropertyLinkItem.

DlgPropertyLink, the link selection dialog, is now made modeless, so
that that user can select geometry sub-element directory from 3D view.
This commit is contained in:
Zheng, Lei
2020-01-22 17:13:47 +08:00
committed by WandererFan
parent 24d935096d
commit 0633abb70d
10 changed files with 1170 additions and 719 deletions

View File

@@ -832,6 +832,9 @@ public:
virtual Property *Copy(void) const override;
virtual void Paste(const Property &from) override;
virtual const char* getEditorName(void) const override
{ return "Gui::PropertyEditor::PropertyLinkItem"; }
/// Return a copy of the property if any changes caused by importing external object
virtual Property *CopyOnImportExternal(const std::map<std::string,std::string> &nameMap) const override;
@@ -974,6 +977,9 @@ public:
virtual Property *Copy(void) const override;
virtual void Paste(const Property &from) override;
virtual const char* getEditorName(void) const override
{ return "Gui::PropertyEditor::PropertyLinkListItem"; }
/// Return a copy of the property if any changes caused by importing external object
virtual Property *CopyOnImportExternal(const std::map<std::string,std::string> &nameMap) const override;
@@ -1248,6 +1254,9 @@ public:
virtual Property *Copy(void) const override;
virtual void Paste(const Property &from) override;
virtual const char* getEditorName(void) const override
{ return "Gui::PropertyEditor::PropertyLinkListItem"; }
virtual Property *CopyOnImportExternal(const std::map<std::string,std::string> &nameMap) const override;
virtual Property *CopyOnLabelChange(App::DocumentObject *obj,

File diff suppressed because it is too large Load Diff

View File

@@ -26,42 +26,100 @@
#include <QDialog>
#include <QAbstractItemView>
#include <QTimer>
#include <QPushButton>
#include <QPointer>
#define FC_XLINK_VALUE_INDEX 5
namespace Gui { namespace Dialog {
class Ui_DlgPropertyLink;
class DlgPropertyLink : public QDialog
class DlgPropertyLink : public QDialog, public Gui::SelectionObserver
{
Q_OBJECT
public:
DlgPropertyLink(const QStringList& list, QWidget* parent = 0, Qt::WindowFlags fl = 0, bool xlink=false);
DlgPropertyLink(QWidget* parent = 0);
~DlgPropertyLink();
void setSelectionMode(QAbstractItemView::SelectionMode mode);
void accept();
QStringList propertyLink() const;
QVariantList propertyLinkList() const;
QList<App::SubObjectT> currentLinks() const;
QList<App::SubObjectT> originalLinks() const;
void init(const App::DocumentObjectT &prop, bool tryFilter=true);
static QString linksToPython(QList<App::SubObjectT> links);
static QList<App::SubObjectT> getLinksFromProperty(const App::PropertyLinkBase *prop);
static QString formatObject(App::Document *ownerDoc, App::DocumentObject *obj, const char *sub);
static inline QString formatObject(App::Document *ownerDoc, const App::SubObjectT &sobj) {
return formatObject(ownerDoc, sobj.getObject(), sobj.getSubName().c_str());
}
static QString formatLinks(App::Document *ownerDoc, QList<App::SubObjectT> links);
protected:
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);
void closeEvent (QCloseEvent * e);
void leaveEvent(QEvent *);
bool eventFilter(QObject *obj, QEvent *ev);
void keyPressEvent(QKeyEvent *ev);
void detachObserver();
void attachObserver();
void onSelectionChanged(const Gui::SelectionChanges& msg);
private Q_SLOTS:
void on_checkObjectType_toggled(bool);
void on_typeTree_itemSelectionChanged();
void on_searchBox_textChanged(const QString&);
void on_comboBox_currentIndexChanged(int);
void onItemExpanded(QTreeWidgetItem * item);
void onItemSelectionChanged();
void onItemEntered(QTreeWidgetItem *item);
void onItemSearch();
void onTimer();
void onClicked(QAbstractButton *);
private:
QTreeWidgetItem *createItem(App::DocumentObject *obj, QTreeWidgetItem *parent);
void findObjects();
QTreeWidgetItem *createTypeItem(Base::Type type);
void filterObjects();
void filterItem(QTreeWidgetItem *item);
bool filterType(QTreeWidgetItem *item);
QTreeWidgetItem *findItem(App::DocumentObject *obj, const char *subname=0, bool *found=nullptr);
void itemSearch(const QString &text, bool select);
QList<App::SubObjectT> getLinkFromItem(QTreeWidgetItem *, bool needSubName=true) const;
private:
QStringList link;
Ui_DlgPropertyLink* ui;
QTimer *timer;
QPushButton *resetButton;
QPushButton *refreshButton;
QPointer<QWidget> parentView;
std::vector<App::SubObjectT> savedSelections;
App::DocumentObjectT objProp;
std::set<App::DocumentObject*> inList;
std::set<std::string> types;
bool refreshTypes = true;
std::map<App::Document*, QTreeWidgetItem*> docItems;
std::map<App::DocumentObject*, QTreeWidgetItem*> itemMap;
std::map<QByteArray, QTreeWidgetItem*> typeItems;
std::set<QTreeWidgetItem*> subSelections;
QList<QTreeWidgetItem*> selections;
std::set<QByteArray> selectedTypes;
QList<App::SubObjectT> oldLinks;
bool allowSubObject = false;
bool singleSelect = false;
bool singleParent = false;
App::DocumentObject *currentObj = nullptr;
QTreeWidgetItem *searchItem = nullptr;
QBrush bgBrush;
};
} // namespace Dialog

View File

@@ -14,28 +14,6 @@
<string>Link</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0">
<widget class="QCheckBox" name="checkObjectType">
<property name="text">
<string>Filter by type</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QTreeWidget" name="treeWidget">
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@@ -46,7 +24,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="searchBox">
<widget class="Gui::ExpressionLineEdit" name="searchBox">
<property name="toolTip">
<string>A search pattern to filter the results above</string>
</property>
@@ -54,22 +32,18 @@
</item>
</layout>
</item>
<item row="7" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="2" column="0">
<widget class="QTreeWidget" name="typeTree">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
<widget class="QTreeWidget" name="treeWidget">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="rootIsDecorated">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerVisible">
@@ -82,8 +56,57 @@
</column>
</widget>
</item>
<item row="2" column="0">
<widget class="QTreeWidget" name="typeTree">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="7" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkObjectType">
<property name="text">
<string>Filter by type</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::ExpressionLineEdit</class>
<extends>QLineEdit</extends>
<header location="global">Gui/ExpressionCompleter.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>treeWidget</tabstop>
<tabstop>checkObjectType</tabstop>
<tabstop>typeTree</tabstop>
<tabstop>searchBox</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@@ -36,6 +36,10 @@ public:
setDocumentObject(obj);
}
void setNoProperty(bool enabled) {
noProperty = enabled;
}
void setDocumentObject(const App::DocumentObject *obj) {
beginResetModel();
if(obj) {
@@ -337,6 +341,13 @@ void ExpressionCompleter::setDocumentObject(const App::DocumentObject *obj) {
static_cast<ExpressionCompleterModel*>(m)->setDocumentObject(obj);
}
void ExpressionCompleter::setNoProperty(bool enabled) {
noProperty = enabled;
auto m = model();
if(m)
static_cast<ExpressionCompleterModel*>(m)->setNoProperty(enabled);
}
QString ExpressionCompleter::pathFromIndex ( const QModelIndex & index ) const
{
auto m = model();
@@ -545,6 +556,12 @@ void ExpressionLineEdit::setDocumentObject(const App::DocumentObject * currentDo
}
}
void ExpressionLineEdit::setNoProperty(bool enabled) {
noProperty = enabled;
if(completer)
completer->setNoProperty(enabled);
}
bool ExpressionLineEdit::completerActive() const
{
return completer && completer->popup() && completer->popup()->isVisible();

View File

@@ -42,6 +42,8 @@ public:
void setDocumentObject(const App::DocumentObject*);
void setNoProperty(bool enabled=true);
public Q_SLOTS:
void slotUpdate(const QString &prefix, int pos);
@@ -65,6 +67,7 @@ public:
void setDocumentObject(const App::DocumentObject *currentDocObj);
bool completerActive() const;
void hideCompleter();
void setNoProperty(bool enabled=true);
Q_SIGNALS:
void textChanged2(QString text, int pos);
public Q_SLOTS:

View File

@@ -27,6 +27,7 @@
#include <Base/Matrix.h>
#include <Base/Placement.h>
#include <Base/Quantity.h>
#include <App/DocumentObserver.h>
Q_DECLARE_METATYPE(Base::Vector3f)
Q_DECLARE_METATYPE(Base::Vector3d)
@@ -34,5 +35,7 @@ Q_DECLARE_METATYPE(Base::Matrix4D)
Q_DECLARE_METATYPE(Base::Placement)
Q_DECLARE_METATYPE(Base::Quantity)
Q_DECLARE_METATYPE(QList<Base::Quantity>)
Q_DECLARE_METATYPE(App::SubObjectT)
Q_DECLARE_METATYPE(QList<App::SubObjectT>)
#endif // GUI_METATYPES_H

View File

@@ -861,7 +861,7 @@ void View3DInventorViewer::checkGroupOnTop(const SelectionChanges &Reason) {
return;
}
if(childRoot->findChild(childVp->getRoot())<0) {
FC_WARN("cannot find '" << childVp->getObject()->getFullName()
FC_LOG("cannot find '" << childVp->getObject()->getFullName()
<< "' in geo group '" << grp->getNameInDocument() << "'");
break;
}

View File

@@ -54,6 +54,7 @@
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
#include <Gui/MainWindow.h>
#include <Gui/ViewProviderDocumentObject.h>
#include <Gui/Placement.h>
#include <Gui/FileDialog.h>
@@ -65,6 +66,7 @@
#include <Gui/SpinBox.h>
using namespace Gui::PropertyEditor;
using namespace Gui::Dialog;
Gui::PropertyEditor::PropertyItemFactory* Gui::PropertyEditor::PropertyItemFactory::_singleton = NULL;
@@ -3572,7 +3574,7 @@ QVariant PropertyTransientFileItem::editorData(QWidget *editor) const
// ---------------------------------------------------------------
LinkSelection::LinkSelection(const QStringList& list) : link(list)
LinkSelection::LinkSelection(const App::SubObjectT &link) : link(link)
{
}
@@ -3582,15 +3584,23 @@ LinkSelection::~LinkSelection()
void LinkSelection::select()
{
auto sobj = link.getSubObject();
if(!sobj) {
QMessageBox::critical(getMainWindow(), tr("Error"), tr("Object not found"));
return;
}
Gui::Selection().selStackPush();
Gui::Selection().clearSelection();
Gui::Selection().addSelection((const char*)link[0].toLatin1(),
(const char*)link[1].toLatin1());
Gui::Selection().addSelection(link.getDocumentName().c_str(),
link.getObjectName().c_str(),
link.getSubName().c_str());
this->deleteLater();
}
// ---------------------------------------------------------------
LinkLabel::LinkLabel (QWidget * parent, bool xlink) : QWidget(parent), isXLink(xlink)
LinkLabel::LinkLabel (QWidget * parent, const App::Property *prop)
: QWidget(parent), objProp(prop), dlg(nullptr)
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
@@ -3599,6 +3609,8 @@ LinkLabel::LinkLabel (QWidget * parent, bool xlink) : QWidget(parent), isXLink(x
label = new QLabel(this);
label->setAutoFillBackground(true);
label->setTextFormat(Qt::RichText);
// Below is necessary for the hytperlink to be clickable without losing focus
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
layout->addWidget(label);
editButton = new QPushButton(QLatin1String("..."), this);
@@ -3620,23 +3632,42 @@ LinkLabel::~LinkLabel()
{
}
void LinkLabel::setPropertyLink(const QStringList& o)
void LinkLabel::updatePropertyLink()
{
link = o;
QString linkcolor = QApplication::palette().color(QPalette::Link).name();
QString text = QString::fromLatin1(
"<html><head><style type=\"text/css\">"
"p, li { white-space: pre-wrap; }"
"</style></head><body>"
"<p>"
"<a href=\"%1.%2\"><span style=\" text-decoration: underline; color:%3;\">%4</span></a>"
"</p></body></html>"
)
.arg(link[0], link[1], linkcolor, link[2]);
QString text;
auto owner = objProp.getObject();
auto prop = Base::freecad_dynamic_cast<App::PropertyLinkBase>(objProp.getProperty());
link = QVariant();
if(owner && prop) {
auto links = DlgPropertyLink::getLinksFromProperty(prop);
if(links.size() == 1) {
auto &sobj = links.front();
link = QVariant::fromValue(sobj);
QString linkcolor = QApplication::palette().color(QPalette::Link).name();
text = QString::fromLatin1(
"<html><head><style type=\"text/css\">"
"p, li { white-space: pre-wrap; }"
"</style></head><body>"
"<p>"
"<a href=\"%1#%2.%3\"><span style=\" text-decoration: underline; color:%4;\">%5</span></a>"
"</p></body></html>"
)
.arg(QLatin1String(sobj.getDocumentName().c_str()),
QLatin1String(sobj.getObjectName().c_str()),
QString::fromUtf8(sobj.getSubName().c_str()),
linkcolor,
DlgPropertyLink::formatObject(
owner->getDocument(), sobj.getObject(), sobj.getSubName().c_str()));
} else if (links.size()) {
text = DlgPropertyLink::formatLinks(owner->getDocument(), links);
}
}
label->setText(text);
}
QStringList LinkLabel::propertyLink() const
QVariant LinkLabel::propertyLink() const
{
return link;
}
@@ -3644,50 +3675,71 @@ QStringList LinkLabel::propertyLink() const
void LinkLabel::onLinkActivated (const QString& s)
{
Q_UNUSED(s);
LinkSelection* select = new LinkSelection(link);
LinkSelection* select = new LinkSelection(qvariant_cast<App::SubObjectT>(link));
QTimer::singleShot(50, select, SLOT(select()));
}
void LinkLabel::onEditClicked ()
{
Gui::Dialog::DlgPropertyLink dlg(link, this, 0, isXLink);
if (dlg.exec() == QDialog::Accepted) {
setPropertyLink(dlg.propertyLink());
/*emit*/ linkChanged(link);
if(!dlg) {
dlg = new DlgPropertyLink(this);
dlg->init(objProp,true);
connect(dlg, SIGNAL(accepted()), this, SLOT(onLinkChanged()));
} else
dlg->init(objProp,false);
dlg->show();
}
void LinkLabel::onLinkChanged() {
if(dlg) {
auto links = dlg->currentLinks();
if(links != dlg->originalLinks()) {
link = QVariant::fromValue(links);
/*emit*/ linkChanged(link);
updatePropertyLink();
}
}
}
void LinkLabel::resizeEvent(QResizeEvent* e)
{
editButton->setFixedWidth(e->size().height());
editButton->setFixedHeight(e->size().height());
}
// --------------------------------------------------------------------
PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyLinkItem)
PropertyLinkItem::PropertyLinkItem():isXLink(false)
PropertyLinkItem::PropertyLinkItem()
{
}
QVariant PropertyLinkItem::toString(const QVariant& prop) const
{
QStringList list = prop.toStringList();
return QVariant(list[2]);
QString res;
if(propertyItems.size()) {
App::DocumentObjectT owner(propertyItems[0]);
res = DlgPropertyLink::formatLinks(owner.getDocument(),
qvariant_cast<QList<App::SubObjectT> >(prop));
}
return res;
}
QVariant PropertyLinkItem::data(int column, int role) const {
if(propertyItems.size() && column == 1
&& (role == Qt::TextColorRole || role == Qt::ToolTipRole))
{
auto xlink = Base::freecad_dynamic_cast<const App::PropertyXLink>(propertyItems[0]);
if(xlink) {
if(role==Qt::TextColorRole && xlink->checkRestore()>1)
auto propLink = Base::freecad_dynamic_cast<const App::PropertyLinkBase>(propertyItems[0]);
if(propLink) {
if(role==Qt::TextColorRole && propLink->checkRestore()>1)
return QVariant::fromValue(QColor(0xff,0,0));
else if(role == Qt::ToolTipRole) {
const char *filePath = xlink->getFilePath();
if(filePath && filePath[0])
return QVariant::fromValue(QString::fromUtf8(filePath));
auto xlink = Base::freecad_dynamic_cast<const App::PropertyXLink>(propertyItems[0]);
if(xlink) {
const char *filePath = xlink->getFilePath();
if(filePath && filePath[0])
return QVariant::fromValue(QString::fromUtf8(filePath));
}
}
}
}
@@ -3696,365 +3748,55 @@ QVariant PropertyLinkItem::data(int column, int role) const {
QVariant PropertyLinkItem::value(const App::Property* prop) const
{
assert(prop && prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId()));
auto propLink = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
if(!propLink)
return QVariant();
auto xlink = Base::freecad_dynamic_cast<const App::PropertyXLink>(prop);
isXLink = xlink!=0;
auto links = DlgPropertyLink::getLinksFromProperty(propLink);
if(links.empty())
return QVariant();
const App::PropertyLink* prop_link = static_cast<const App::PropertyLink*>(prop);
App::PropertyContainer* c = prop_link->getContainer();
// The list has five mandatory elements:
//
// document name of the container,
// internal name of the linked object,
// label,
// internal name of container,
// property name
//
// and two additional elements if it is a PropertyXLink
//
// subname
// (optional) document name of linked object if it is different from the container
//
App::DocumentObject* obj = prop_link->getValue();
QStringList list;
if (obj) {
list << QString::fromLatin1(obj->getDocument()->getName());
list << QString::fromLatin1(obj->getNameInDocument());
std::string _objName;
const char *objName = obj->getNameInDocument();
auto owner = Base::freecad_dynamic_cast<App::DocumentObject>(c);
if(!objName || (owner && owner->getDocument()!=obj->getDocument())) {
_objName = obj->getFullName();
objName = _objName.c_str();
}
if(xlink && xlink->getSubValues().size()) {
int count = 0;
std::stringstream ss;
ss << objName << ' ';
std::string prevSub;
for(const auto &sub : xlink->getSubValues(false)) {
if(++count > 3)
break;
if(count>1)
ss << ',';
else
ss << '(';
auto element = Data::ComplexGeoData::findElementName(sub.c_str());
if(prevSub.size()==(std::size_t)(element-sub.c_str())
&& boost::starts_with(sub,prevSub))
{
ss << element;
continue;
}
prevSub.clear();
if(element && element[0])
prevSub = sub.substr(0,element-sub.c_str());
if(count > 1)
ss << ' ';
ss << sub;
}
if(count) {
if(count>3)
ss << "...";
ss << ')';
}
list << QString::fromUtf8(ss.str().c_str());
}else if(obj->Label.getStrValue() != objName) {
list << QString::fromLatin1("%1 (%2)").
arg(QString::fromUtf8(obj->Label.getValue()),
QString::fromLatin1(objName));
} else {
list << QString::fromUtf8(obj->Label.getValue());
}
} else {
// no object assigned
// the document name
if (c->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(c);
list << QString::fromLatin1(obj->getDocument()->getName());
}
else {
list << QString::fromLatin1("");
}
// the internal object name
list << QString::fromLatin1("Null");
// the object label
std::string msg;
if(xlink && xlink->checkRestore(&msg)>1)
list << QString::fromUtf8(msg.c_str());
else
list << QString::fromLatin1("");
}
// the name of this object
if (c->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(c);
list << QString::fromLatin1(obj->getNameInDocument());
}
else
list << QString::fromLatin1("Null");
list << QString::fromLatin1(prop->getName());
assert(list.size() == FC_XLINK_VALUE_INDEX);
if(xlink) {
list << QString::fromUtf8(xlink->getSubName(false));
auto cobj = dynamic_cast<App::DocumentObject*>(c);
if(cobj && obj && cobj->getDocument()!=obj->getDocument())
list << QString::fromLatin1(obj->getDocument()->getName());
}
return QVariant(list);
return QVariant::fromValue(links);
}
void PropertyLinkItem::setValue(const QVariant& value)
{
if (!value.canConvert(QVariant::StringList))
return;
QStringList items = value.toStringList();
if (items.size() > 1) {
QString d = items[0];
QString o = items[1];
QString data;
if ( o.isEmpty() )
data = QString::fromLatin1("None");
else if(isXLink && items.size()>FC_XLINK_VALUE_INDEX+1) {
QString doc;
if(items.size()>=FC_XLINK_VALUE_INDEX+2)
doc = items[FC_XLINK_VALUE_INDEX+1];
else
doc = d;
data = QString::fromLatin1("(App.getDocument('%1').getObject('%2'),'%3')").
arg(doc,o,items[FC_XLINK_VALUE_INDEX]);
}else
data = QString::fromLatin1("App.getDocument('%1').getObject('%2')").arg(d,o);
setPropertyValue(data);
}
auto links = qvariant_cast<QList<App::SubObjectT> >(value);
setPropertyValue(DlgPropertyLink::linksToPython(links));
}
QWidget* PropertyLinkItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
LinkLabel *ll = new LinkLabel(parent, isXLink);
if(propertyItems.empty())
return 0;
LinkLabel *ll = new LinkLabel(parent, propertyItems.front());
ll->setAutoFillBackground(true);
ll->setDisabled(isReadOnly());
QObject::connect(ll, SIGNAL(linkChanged(const QStringList&)), receiver, method);
QObject::connect(ll, SIGNAL(linkChanged(const QVariant&)), receiver, method);
return ll;
}
void PropertyLinkItem::setEditorData(QWidget *editor, const QVariant& data) const
{
QStringList list = data.toStringList();
(void)data;
LinkLabel *ll = static_cast<LinkLabel*>(editor);
ll->setPropertyLink(list);
return ll->updatePropertyLink();
}
QVariant PropertyLinkItem::editorData(QWidget *editor) const
{
LinkLabel *ll = static_cast<LinkLabel*>(editor);
return QVariant(ll->propertyLink());
return ll->propertyLink();
}
// --------------------------------------------------------------------
LinkListLabel::LinkListLabel (QWidget * parent) : QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(1);
label = new QLabel(this);
label->setAutoFillBackground(true);
layout->addWidget(label);
editButton = new QPushButton(QLatin1String("..."), this);
editButton->setToolTip(tr("Change the linked objects"));
layout->addWidget(editButton);
// setLayout(layout);
connect(editButton, SIGNAL(clicked()),
this, SLOT(onEditClicked()));
}
LinkListLabel::~LinkListLabel()
{
}
void LinkListLabel::setPropertyLinkList(const QVariantList& o)
{
links = o;
if (links.isEmpty()) {
label->clear();
}
else if (links.size() == 1) {
QStringList s = links.front().toStringList();
label->setText(s[2]);
}
else {
QStringList obj;
for (QVariantList::iterator it = links.begin(); it != links.end(); ++it)
obj << it->toStringList()[2];
label->setText(QString::fromLatin1("[%1]").arg(obj.join(QString::fromLatin1(", "))));
}
}
QVariantList LinkListLabel::propertyLinkList() const
{
return links;
}
void LinkListLabel::onEditClicked ()
{
QStringList list = links.front().toStringList();
Gui::Dialog::DlgPropertyLink dlg(list, this);
dlg.setSelectionMode(QAbstractItemView::ExtendedSelection);
if (dlg.exec() == QDialog::Accepted) {
setPropertyLinkList(dlg.propertyLinkList());
Q_EMIT linkChanged(links);
}
}
void LinkListLabel::resizeEvent(QResizeEvent* e)
{
editButton->setFixedWidth(e->size().height());
}
PROPERTYITEM_SOURCE(Gui::PropertyEditor::PropertyLinkListItem)
PropertyLinkListItem::PropertyLinkListItem()
{
}
QVariant PropertyLinkListItem::toString(const QVariant& prop) const
{
QVariantList list = prop.toList();
if (list.empty()) {
return QString();
}
else if (list.size() == 1) {
QStringList item = list.front().toStringList();
return QString::fromLatin1("%1").arg(item[2]);
}
else {
QStringList obj;
for (QVariantList::iterator it = list.begin(); it != list.end(); ++it)
obj << it->toStringList()[2];
return QString::fromLatin1("[%1]").arg(obj.join(QString::fromLatin1(", ")));
}
}
QVariant PropertyLinkListItem::value(const App::Property* prop) const
{
assert(prop && prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId()));
const App::PropertyLinkList* prop_link = static_cast<const App::PropertyLinkList*>(prop);
App::PropertyContainer* c = prop_link->getContainer();
// the name of this object
QString objName;
if (c->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(c);
objName = QString::fromLatin1(obj->getNameInDocument());
}
else {
objName = QString::fromLatin1("Null");
}
// each item is a list of five elements:
//[document name, internal name, label, internal name of container, property name]
// the variant list contains at least one item
std::vector<App::DocumentObject*> obj = prop_link->getValues();
QVariantList varList;
if (!obj.empty()) {
for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) {
QStringList list;
list << QString::fromLatin1((*it)->getDocument()->getName());
list << QString::fromLatin1((*it)->getNameInDocument());
list << QString::fromUtf8((*it)->Label.getValue());
list << objName;
list << QString::fromLatin1(prop->getName());
varList << list;
}
}
else {
QStringList list;
// no object assigned
// the document name
if (c->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(c);
list << QString::fromLatin1(obj->getDocument()->getName());
}
else {
list << QString::fromLatin1("");
}
// the internal object name
list << QString::fromLatin1("Null");
// the object label
list << QString::fromLatin1("");
list << objName;
list << QString::fromLatin1(prop->getName());
varList << list;
}
return QVariant(varList);
}
void PropertyLinkListItem::setValue(const QVariant& value)
{
if (!value.canConvert(QVariant::List))
return;
QVariantList items = value.toList();
QStringList data;
for (QVariantList::iterator it = items.begin(); it != items.end(); ++it) {
QStringList list = it->toStringList();
QString d = list[0];
QString o = list[1];
if (!o.isEmpty())
data << QString::fromLatin1("App.getDocument('%1').getObject('%2')").arg(d, o);
}
if(data.size()==0)
setPropertyValue(QLatin1String("[]"));
else
setPropertyValue(QString::fromLatin1("[%1]").arg(data.join(QString::fromLatin1(", "))));
}
QWidget* PropertyLinkListItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
LinkListLabel *ll = new LinkListLabel(parent);
ll->setAutoFillBackground(true);
ll->setDisabled(isReadOnly());
QObject::connect(ll, SIGNAL(linkChanged(const QVariantList&)), receiver, method);
return ll;
}
void PropertyLinkListItem::setEditorData(QWidget *editor, const QVariant& data) const
{
QVariantList list = data.toList();
LinkListLabel *ll = static_cast<LinkListLabel*>(editor);
ll->setPropertyLinkList(list);
}
QVariant PropertyLinkListItem::editorData(QWidget *editor) const
{
LinkListLabel *ll = static_cast<LinkListLabel*>(editor);
return QVariant(ll->propertyLinkList());
}
// --------------------------------------------------------------------
PropertyItemEditorFactory::PropertyItemEditorFactory()

View File

@@ -35,6 +35,7 @@
#include <Base/Placement.h>
#include <Base/Quantity.h>
#include <Base/UnitsApi.h>
#include <App/DocumentObserver.h>
#include <App/PropertyStandard.h>
#include <Gui/Widgets.h>
#include <Gui/ExpressionBinding.h>
@@ -63,7 +64,12 @@ void _class_::init(void) { \
}
namespace Gui {
namespace Dialog { class TaskPlacement; }
namespace Dialog {
class TaskPlacement;
class DlgPropertyLink;
}
namespace PropertyEditor {
class PropertyItem;
@@ -945,25 +951,26 @@ class LinkSelection : public QObject
Q_OBJECT
public:
LinkSelection(const QStringList&);
LinkSelection(const App::SubObjectT &);
~LinkSelection();
public Q_SLOTS:
void select();
private:
QStringList link;
App::SubObjectT link;
};
class LinkLabel : public QWidget
{
Q_OBJECT
public:
LinkLabel (QWidget * parent = 0, bool xlink = false);
LinkLabel (QWidget * parent, const App::Property *prop);
virtual ~LinkLabel();
void setPropertyLink(const QStringList& o);
QStringList propertyLink() const;
void updatePropertyLink();
QVariant propertyLink() const;
protected:
void resizeEvent(QResizeEvent*);
@@ -971,15 +978,18 @@ protected:
protected Q_SLOTS:
void onLinkActivated(const QString&);
void onEditClicked();
void onLinkChanged();
Q_SIGNALS:
void linkChanged(const QStringList&);
void linkChanged(const QVariant&);
private:
QLabel* label;
QPushButton* editButton;
QStringList link;
bool isXLink;
QVariant link;
App::DocumentObjectT objProp;
Gui::Dialog::DlgPropertyLink* dlg;
};
/**
@@ -1003,54 +1013,17 @@ protected:
protected:
PropertyLinkItem();
private:
mutable bool isXLink;
};
class LinkListLabel : public QWidget
{
Q_OBJECT
public:
LinkListLabel (QWidget * parent = 0);
virtual ~LinkListLabel();
void setPropertyLinkList(const QVariantList& o);
QVariantList propertyLinkList() const;
protected:
void resizeEvent(QResizeEvent*);
protected Q_SLOTS:
void onEditClicked();
Q_SIGNALS:
void linkChanged(const QVariantList&);
private:
QLabel* label;
QPushButton* editButton;
QVariantList links;
};
/**
* Edit properties of link list type.
* \author Werner Mayer
*/
class GuiExport PropertyLinkListItem: public PropertyItem
class GuiExport PropertyLinkListItem: public PropertyLinkItem
{
Q_OBJECT
PROPERTYITEM_HEADER
virtual QWidget* createEditor(QWidget* parent, const QObject* receiver, const char* method) const;
virtual void setEditorData(QWidget *editor, const QVariant& data) const;
virtual QVariant editorData(QWidget *editor) const;
protected:
virtual QVariant toString(const QVariant&) const;
virtual QVariant value(const App::Property*) const;
virtual void setValue(const QVariant&);
protected:
PropertyLinkListItem();
};