Gui: refactor Object Selection Dialog

It is originally used for dependency selection when copying object.
Modified to improve auto dependency selection, and for use by Link
configuration object setup, which also involves dependency selection.
This commit is contained in:
Zheng, Lei
2022-03-15 21:33:07 +08:00
committed by Chris Hennes
parent c6d87e69b5
commit 5947f91b17
5 changed files with 788 additions and 370 deletions

View File

@@ -24,6 +24,7 @@
#ifndef _PreComp_
# include <QPushButton>
# include <QTreeWidget>
# include <QCheckBox>
#endif
#include <App/Document.h>
@@ -32,8 +33,10 @@
#include "DlgObjectSelection.h"
#include "ui_DlgObjectSelection.h"
#include "Application.h"
#include "MainWindow.h"
#include "ViewProviderDocumentObject.h"
#include "MetaTypes.h"
#include "ViewParams.h"
FC_LOG_LEVEL_INIT("Gui",true,true)
@@ -43,90 +46,115 @@ using namespace Gui;
DlgObjectSelection::DlgObjectSelection(
const std::vector<App::DocumentObject*> &objs, QWidget* parent, Qt::WindowFlags fl)
: QDialog(parent, fl), ui(new Ui_DlgObjectSelection)
: QDialog(parent, fl)
{
/**
* make a copy of the originally selected objects
* so we can return them if the user clicks useOriginalsBtn
*/
this->originalSelections = objs;
init(objs, {});
}
DlgObjectSelection::DlgObjectSelection(
const std::vector<App::DocumentObject*> &objs,
const std::vector<App::DocumentObject*> &excludes,
QWidget* parent,
Qt::WindowFlags fl)
: QDialog(parent, fl)
{
init(objs, excludes);
}
static bool inline setCheckState(QTreeWidgetItem *item, Qt::CheckState state, bool forced=true)
{
if (!forced) {
if (item->isSelected()) {
if (state == Qt::Unchecked || item->checkState(0) == Qt::Unchecked)
return false;
}
if (item->checkState(0) == state)
return false;
}
// auto objT = qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole));
// FC_MSG(objT.getObjectFullName() << (state == Qt::Unchecked ? " unchecked" :
// (state == Qt::Checked ? " checked" : " partial")));
item->setCheckState(0, state);
return true;
}
void DlgObjectSelection::init(const std::vector<App::DocumentObject*> &objs,
const std::vector<App::DocumentObject*> &excludes)
{
initSels = objs;
std::sort(initSels.begin(), initSels.end());
deps = App::Document::getDependencyList(objs, App::Document::DepSort);
depSet.insert(deps.begin(), deps.end());
ui = new Ui_DlgObjectSelection;
ui->setupUi(this);
hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General");
ui->checkBoxAutoDeps->setChecked(hGrp->GetBool("ObjectSelectionAutoDeps", true));
connect(ui->checkBoxAutoDeps, SIGNAL(toggled(bool)), this, SLOT(onAutoDeps(bool)));
// make sure to show a horizontal scrollbar if needed
ui->depList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->depList->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->depList->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
ui->depList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
ui->inList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->inList->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->inList->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
ui->treeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
ui->depList->header()->setStretchLastSection(false);
ui->depList->headerItem()->setText(0, tr("Dependency"));
ui->depList->headerItem()->setText(0, tr("Depending on"));
ui->depList->headerItem()->setText(1, tr("Document"));
ui->depList->headerItem()->setText(2, tr("Name"));
ui->depList->headerItem()->setText(3, tr("State"));
ui->treeWidget->headerItem()->setText(0, tr("Hierarchy"));
ui->inList->headerItem()->setText(0, tr("Depended by"));
ui->inList->headerItem()->setText(1, tr("Document"));
ui->inList->headerItem()->setText(2, tr("Name"));
ui->treeWidget->headerItem()->setText(0, tr("Selections"));
ui->treeWidget->header()->setStretchLastSection(false);
for(auto obj : App::Document::getDependencyList(objs)) {
auto &info = objMap[obj];
info.depItem = new QTreeWidgetItem(ui->depList);
auto vp = Gui::Application::Instance->getViewProvider(obj);
if(vp) info.depItem->setIcon(0, vp->getIcon());
info.depItem->setText(0, QString::fromUtf8((obj)->Label.getValue()));
info.depItem->setText(1, QString::fromUtf8(obj->getDocument()->getName()));
info.depItem->setText(2, QString::fromLatin1(obj->getNameInDocument()));
info.depItem->setText(3, tr("Selected"));
info.depItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
info.depItem->setCheckState(0,Qt::Checked);
}
for(auto obj : objs) {
auto &info = objMap[obj];
info.items.push_back(createItem(obj,nullptr));
info.items.back()->setCheckState(0,Qt::Checked);
}
for(auto &v : objMap) {
for(auto obj : v.first->getOutListRecursive()) {
if(obj == v.first)
continue;
auto it = objMap.find(obj);
if(it == objMap.end())
continue;
v.second.outList[obj] = &it->second;
}
for(auto obj : v.first->getInListRecursive()) {
if(obj == v.first)
continue;
auto it = objMap.find(obj);
if(it == objMap.end())
continue;
v.second.inList[obj] = &it->second;
}
}
/**
* create useOriginalsBtn and add to the button box
* tried adding to .ui file, but could never get the
* formatting exactly the way I wanted it. -- <TheMarkster>
*/
useOriginalsBtn = new QPushButton(tr("&Use Original Selections"));
useOriginalsBtn->setToolTip(tr("Ignore dependencies and proceed with objects\noriginally selected prior to opening this dialog"));
ui->buttonBox->addButton(useOriginalsBtn,QDialogButtonBox::ActionRole);
connect(ui->treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)),
this, SLOT(onItemExpanded(QTreeWidgetItem*)));
allItem = new QTreeWidgetItem(ui->treeWidget);
allItem->setText(0, QStringLiteral("<%1>").arg(tr("All")));
QFont font = allItem->font(0);
font.setBold(true);
allItem->setFont(0, font);
allItem->setFlags(Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
allItem->setCheckState(0, Qt::Checked);
for(auto obj : initSels)
getItem(obj)->setCheckState(0, Qt::Checked);
for(auto obj : deps)
getItem(obj)->setCheckState(0, Qt::Checked);
auto filter = excludes;
std::sort(filter.begin(), filter.end());
for (auto obj : deps) {
auto it = std::lower_bound(filter.begin(), filter.end(), obj);
if (it != filter.end() && *it == obj)
setItemState(obj, Qt::Unchecked);
}
onItemSelectionChanged();
connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(onItemChanged(QTreeWidgetItem*,int)));
this, SLOT(onObjItemChanged(QTreeWidgetItem*,int)));
connect(ui->depList, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(onItemChanged(QTreeWidgetItem*,int)));
this, SLOT(onDepItemChanged(QTreeWidgetItem*,int)));
connect(ui->inList, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(onDepItemChanged(QTreeWidgetItem*,int)));
connect(ui->treeWidget, SIGNAL(itemSelectionChanged()),
this, SLOT(onItemSelectionChanged()));
connect(ui->depList, SIGNAL(itemSelectionChanged()),
this, SLOT(onDepSelectionChanged()));
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(useOriginalsBtn, SIGNAL(clicked()), this, SLOT(onUseOriginalsBtnClicked()));
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), this, SLOT(checkItemChanged()));
}
/**
@@ -138,249 +166,427 @@ DlgObjectSelection::~DlgObjectSelection()
delete ui;
}
QTreeWidgetItem *DlgObjectSelection::createItem(App::DocumentObject *obj, QTreeWidgetItem *parent) {
QTreeWidgetItem* item;
if(parent)
item = new QTreeWidgetItem(parent);
else
QTreeWidgetItem *DlgObjectSelection::getItem(App::DocumentObject *obj,
std::vector<QTreeWidgetItem*> **pitems,
QTreeWidgetItem *parent)
{
auto &items = itemMap[App::SubObjectT(obj, "")];
if (pitems)
*pitems = &items;
QTreeWidgetItem *item;
if (!parent) {
if (items.size())
return items[0];
item = new QTreeWidgetItem(ui->treeWidget);
auto vp = Gui::Application::Instance->getViewProvider(obj);
if(vp) item->setIcon(0, vp->getIcon());
item->setText(0, QString::fromUtf8((obj)->Label.getValue()));
item->setData(0, Qt::UserRole, QByteArray(obj->getDocument()->getName()));
item->setData(0, Qt::UserRole+1, QByteArray(obj->getNameInDocument()));
auto vp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
Gui::Application::Instance->getViewProvider(obj));
if (vp) item->setIcon(0, vp->getIcon());
App::SubObjectT objT(obj, "");
item->setText(0, QString::fromUtf8((obj)->Label.getValue()));
if (std::binary_search(initSels.begin(), initSels.end(), obj)) {
QFont font = item->font(0);
font.setBold(true);
font.setItalic(true);
item->setFont(0, font);
}
item->setToolTip(0, QString::fromUtf8(objT.getObjectFullName().c_str()));
item->setData(0, Qt::UserRole, QVariant::fromValue(objT));
item->setChildIndicatorPolicy(obj->getOutList().empty() ?
QTreeWidgetItem::DontShowIndicator : QTreeWidgetItem::ShowIndicator);
} else if (items.size()) {
item = new QTreeWidgetItem(parent);
item->setIcon(0, items[0]->icon(0));
item->setText(0, items[0]->text(0));
item->setFont(0, items[0]->font(0));
item->setToolTip(0, items[0]->toolTip(0));
item->setData(0, Qt::UserRole, items[0]->data(0, Qt::UserRole));
item->setChildIndicatorPolicy(items[0]->childIndicatorPolicy());
item->setCheckState(0, items[0]->checkState(0));
} else
return nullptr;
items.push_back(item);
item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
std::set<App::DocumentObject *> outSet;
for(auto o : obj->getOutList()) {
if(objMap.count(o))
outSet.insert(o);
}
if(outSet.empty())
return item;
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
if(!parent) {
bool populate = false;
for(auto o : outSet) {
if(objMap[o].items.empty()) {
populate = true;
break;
}
}
if(!populate)
return item;
for(auto o : outSet) {
auto &info = objMap[o];
info.items.push_back(createItem(o,item));
info.items.back()->setCheckState(0,info.checkState);
}
}
return item;
}
class SignalBlocker {
public:
SignalBlocker(QTreeWidget *treeWidget)
:treeWidget(treeWidget)
{
treeWidget->blockSignals(true);
}
~SignalBlocker() {
treeWidget->blockSignals(false);
}
QTreeWidget *treeWidget;
};
App::DocumentObject *DlgObjectSelection::objFromItem(QTreeWidgetItem *item) {
std::string name;
std::string docName;
if(item->treeWidget() == ui->treeWidget) {
docName = item->data(0,Qt::UserRole).toByteArray().constData();
name = item->data(0,Qt::UserRole+1).toByteArray().constData();
}else{
docName = qPrintable(item->text(1));
name = qPrintable(item->text(2));
}
auto doc = App::GetApplication().getDocument(docName.c_str());
if(!doc) return nullptr;
return doc->getObject(name.c_str());
}
void DlgObjectSelection::onItemExpanded(QTreeWidgetItem * item) {
if(item->childCount())
void DlgObjectSelection::onItemExpanded(QTreeWidgetItem *item)
{
if (item->childCount())
return;
auto obj = objFromItem(item);
if(!obj)
return;
SignalBlocker blocker(ui->treeWidget);
std::set<App::DocumentObject *> outSet;
for(auto o : obj->getOutList()) {
if(!objMap.count(obj) || !outSet.insert(o).second)
continue;
auto &info = objMap[o];
info.items.push_back(createItem(o,item));
info.items.back()->setCheckState(0,info.checkState);
if (auto obj = qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole)).getObject()) {
QSignalBlocker blocker(ui->treeWidget);
std::set<App::DocumentObject*> set;
for (auto child : obj->getOutList()) {
if (child && set.insert(child).second)
getItem(child, nullptr, item);
}
}
}
void DlgObjectSelection::onItemChanged(QTreeWidgetItem * item, int column) {
if(column) return;
auto obj = objFromItem(item);
if(!obj) return;
auto state = item->checkState(0);
auto it = objMap.find(obj);
if(it == objMap.end() || state == it->second.checkState)
return;
SignalBlocker blocker(ui->treeWidget);
SignalBlocker blocker2(ui->depList);
auto &info = it->second;
info.checkState = state;
void DlgObjectSelection::updateAllItemState()
{
int count = 0;
for (const auto &v : itemMap) {
auto state = v.second[0]->checkState(0);
if (state == Qt::Unchecked) {
if (count) {
allItem->setCheckState(0, Qt::PartiallyChecked);
return;
}
} else {
if (state == Qt::PartiallyChecked) {
allItem->setCheckState(0, Qt::PartiallyChecked);
return;
}
++count;
}
}
if (count && count == (int)itemMap.size())
allItem->setCheckState(0, Qt::Checked);
}
if(item == info.depItem) {
for(auto item : info.items)
item->setCheckState(0,state);
}else{
info.depItem->setCheckState(0,state);
info.depItem->setText(3,state==Qt::Checked?tr("Selected"):QString());
void DlgObjectSelection::setItemState(App::DocumentObject *obj,
Qt::CheckState state,
bool forced)
{
std::vector<QTreeWidgetItem*> *items = nullptr;
auto item = getItem(obj, &items);
if (!setCheckState(item, state, forced))
return;
for (size_t i=1; i<items->size(); ++i)
setCheckState(items->at(i), state, true);
std::vector<App::DocumentObject*> objs = {obj};
if (ui->checkBoxAutoDeps->isChecked() && state == Qt::Checked) {
// If an object is newly checked, check all its dependencies
for (auto o : obj->getOutListRecursive()) {
if (!depSet.count(o) || itemChanged.count(o))
continue;
auto itItem = itemMap.find(o);
if (itItem == itemMap.end() || itItem->second[0]->checkState(0) == state)
continue;
for (auto i : itItem->second)
setCheckState(i, state, true);
objs.push_back(o);
}
}
if(state == Qt::Unchecked) {
for(auto &v : info.outList) {
if(info.inList.count(v.first)) {
// This indicates a dependency loop. The check here is so that
// object selection still works despite of the loop
for(auto obj : objs) {
auto it = inMap.find(obj);
if (it != inMap.end())
setCheckState(it->second, state);
auto itDep = depMap.find(obj);
if (itDep != depMap.end())
setCheckState(itDep->second, state);
// If an object toggles state, we need to revisit all its in-list
// object to update the partial/full checked state.
for (auto o : obj->getInList()) {
if (!depSet.count(o) ||itemChanged.count(o))
continue;
}
if(v.second->checkState == Qt::Unchecked)
auto it = itemMap.find(o);
if (it == itemMap.end() || it->second[0]->checkState(0) == state)
continue;
v.second->checkState = Qt::Unchecked;
v.second->depItem->setText(3,QString());
v.second->depItem->setCheckState(0,Qt::Unchecked);
for(auto item : v.second->items)
item->setCheckState(0,Qt::Unchecked);
}
for(auto &v : info.inList) {
if(v.second->checkState != Qt::Checked)
continue;
v.second->checkState = Qt::PartiallyChecked;
v.second->depItem->setText(3,tr("Partial"));
v.second->depItem->setCheckState(0,Qt::PartiallyChecked);
for(auto item : v.second->items)
item->setCheckState(0,Qt::PartiallyChecked);
}
return;
} else if(state == Qt::Checked) {
for(auto &v : info.outList) {
if(info.inList.count(v.first)) {
// This indicates a dependency loop. The check here is so that
// object selection still works despite of the loop
continue;
}
if(v.second->checkState == Qt::Checked)
continue;
v.second->checkState = Qt::Checked;
v.second->depItem->setText(3,tr("Selected"));
v.second->depItem->setCheckState(0,Qt::Checked);
for(auto item : v.second->items)
item->setCheckState(0,Qt::Checked);
}
bool touched;
do {
touched = false;
for(auto &v : info.inList) {
if(v.second->checkState != Qt::PartiallyChecked)
int count = 0;
int selcount = 0;
for (auto sibling : o->getOutList()) {
if (!depSet.count(sibling))
continue;
bool partial = false;
for(auto &vv : v.second->outList) {
if(vv.second->checkState != Qt::Checked) {
partial = true;
break;
}
++count;
auto it = itemMap.find(sibling);
if (it == itemMap.end())
continue;
auto s = it->second[0]->checkState(0);
if (s == Qt::Unchecked)
continue;
if (it->second[0]->checkState(0) == Qt::PartiallyChecked) {
selcount = -1;
break;
}
if(partial)
continue;
touched = true;
v.second->checkState = Qt::Checked;
v.second->depItem->setText(3,tr("Selected"));
v.second->depItem->setCheckState(0,Qt::Checked);
for(auto item : v.second->items)
item->setCheckState(0,Qt::Checked);
++selcount;
}
}while(touched);
auto state = it->second[0]->checkState(0);
if (state == Qt::Checked && selcount != count)
setItemState(o, Qt::PartiallyChecked, true);
else if (state == Qt::PartiallyChecked && selcount == count)
setItemState(o, Qt::Checked, true);
}
}
}
std::vector<App::DocumentObject*> DlgObjectSelection::getSelections() const {
if (returnOriginals){
return originalSelections;
}
std::vector<App::DocumentObject*> DlgObjectSelection::getSelections(SelectionOptions options) const {
std::vector<App::DocumentObject*> res;
for(auto &v : objMap) {
if(v.second.checkState != Qt::Unchecked)
res.push_back(v.first);
Base::Flags<SelectionOptions> flags(options);
if (!flags.testFlag(SelectionOptions::Invert)) {
for (const auto &v : itemMap) {
if (v.second[0]->checkState(0) == Qt::Unchecked)
continue;
if (auto obj = v.first.getObject())
res.push_back(obj);
}
} else {
for (auto obj : deps) {
auto it = itemMap.find(obj);
if (it == itemMap.end() || it->second[0]->checkState(0) == Qt::Unchecked)
res.push_back(obj);
}
}
if (flags.testFlag(SelectionOptions::Sort))
std::sort(res.begin(), res.end());
return res;
}
void DlgObjectSelection::onDepItemChanged(QTreeWidgetItem * depItem, int column) {
if(column) return;
QSignalBlocker blocker(ui->depList);
QSignalBlocker blocker2(ui->inList);
QSignalBlocker blocker3(ui->treeWidget);
auto state = depItem->checkState(0);
if (depItem->isSelected()) {
for (auto item : depItem->treeWidget()->selectedItems()) {
auto objT = qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole));
auto it = itemMap.find(objT);
if (it == itemMap.end())
continue;
setCheckState(item, state);
for (auto i : it->second)
setCheckState(i, state);
itemChanged[objT] = state;
}
} else {
auto objT = qvariant_cast<App::SubObjectT>(depItem->data(0, Qt::UserRole));
auto it = itemMap.find(objT);
if (it != itemMap.end()) {
itemChanged[objT] = state;
for (auto i : it->second)
setCheckState(i, state);
}
}
timer.start(10);
}
void DlgObjectSelection::onObjItemChanged(QTreeWidgetItem * objItem, int column) {
if(column != 0)
return;
QSignalBlocker blocker3(ui->treeWidget);
auto state = objItem->checkState(0);
if (objItem == allItem) {
if (state == Qt::PartiallyChecked)
return;
ui->treeWidget->selectionModel()->clearSelection();
itemChanged.clear();
timer.stop();
onItemSelectionChanged();
if (state == Qt::Unchecked) {
for (const auto &v : itemMap) {
for (auto i : v.second)
setCheckState(i, Qt::Unchecked);
auto it = depMap.find(v.first);
if (it != depMap.end())
setCheckState(it->second, Qt::Unchecked);
it = inMap.find(v.first);
if (it != inMap.end())
setCheckState(it->second, Qt::Unchecked);
}
} else {
for (auto obj : initSels)
setCheckState(getItem(obj), Qt::Checked);
for (auto obj : deps) {
setCheckState(getItem(obj), Qt::Checked);
auto it = depMap.find(obj);
if (it != depMap.end())
setCheckState(it->second, Qt::Checked);
it = inMap.find(obj);
if (it != inMap.end())
setCheckState(it->second, Qt::Checked);
}
}
return;
}
if (!objItem->isSelected()) {
ui->treeWidget->selectionModel()->clearSelection();
objItem->setSelected(true);
// We treat selected item in tree widget specially in case of checking
// items in depList or inList. To simplify logic, we change selection
// here if an unselected item has been checked.
itemChanged[qvariant_cast<App::SubObjectT>(objItem->data(0, Qt::UserRole))] = state;
onItemSelectionChanged();
}
else {
for (auto item : ui->treeWidget->selectedItems()) {
setCheckState(item, state);
itemChanged[qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole))] = state;
}
}
timer.start(10);
}
static bool getOutList(App::DocumentObject *obj,
std::set<App::DocumentObject*> &visited,
std::vector<App::DocumentObject*> &result)
{
if (!visited.insert(obj).second)
return false;
for (auto o : obj->getOutList()) {
if (getOutList(o, visited, result))
result.push_back(o);
}
return true;
}
void DlgObjectSelection::checkItemChanged() {
QSignalBlocker blocker(ui->depList);
QSignalBlocker blocker2(ui->inList);
QSignalBlocker blocker3(ui->treeWidget);
std::set<App::DocumentObject*> unchecked;
for (auto &v : itemChanged) {
const auto &objT = v.first;
Qt::CheckState state = v.second;
if (auto obj = objT.getObject()) {
if (state == Qt::Unchecked) {
// We'll deal with unchecked item later
if (ui->checkBoxAutoDeps->isChecked())
unchecked.insert(obj);
} else {
// For checked item, setItemState will auto select its
// dependency
setItemState(obj, state, true);
}
}
}
if (unchecked.size()) {
// When some item is unchecked by the user, we need to re-check the
// recursive outlist of the initially selected object, excluding all
// currently unchecked object. And then uncheck any item that does not
// appear in the returned outlist.
for (const auto &v : itemMap) {
auto item = v.second[0];
if (item->checkState(0) == Qt::Unchecked) {
if (auto obj = qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole)).getObject())
unchecked.insert(obj);
}
}
auto outlist = initSels;
for (auto obj : initSels)
getOutList(obj, unchecked, outlist);
std::sort(outlist.begin(), outlist.end());
for (const auto &v : itemMap) {
if (v.second[0]->checkState(0) == Qt::Unchecked)
continue;
if (auto obj = v.first.getObject()) {
if (!std::binary_search(outlist.begin(), outlist.end(), obj))
setItemState(obj, Qt::Unchecked, true);
}
}
}
itemChanged.clear();
updateAllItemState();
}
QTreeWidgetItem *DlgObjectSelection::createDepItem(QTreeWidget *parent, App::DocumentObject *obj)
{
auto item = new QTreeWidgetItem(parent);
if (parent == ui->depList)
depMap[obj] = item;
else
inMap[obj] = item;
App::SubObjectT objT(obj);
auto vp = Gui::Application::Instance->getViewProvider(obj);
if(vp) item->setIcon(0, vp->getIcon());
item->setData(0, Qt::UserRole, QVariant::fromValue(objT));
item->setToolTip(0, QString::fromUtf8(objT.getObjectFullName().c_str()));
item->setText(0, QString::fromUtf8((obj)->Label.getValue()));
if (std::binary_search(initSels.begin(), initSels.end(), obj)) {
QFont font = item->font(0);
font.setBold(true);
font.setItalic(true);
item->setFont(0, font);
}
item->setText(1, QString::fromUtf8(obj->getDocument()->getName()));
item->setText(2, QString::fromUtf8(obj->getNameInDocument()));
item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
auto it = itemMap.find(obj);
if (it != itemMap.end())
setCheckState(item, it->second[0]->checkState(0));
return item;
}
void DlgObjectSelection::onItemSelectionChanged() {
SignalBlocker block2(ui->treeWidget);
SignalBlocker block(ui->depList);
QTreeWidgetItem *scroll=nullptr;
for(auto &v : objMap) {
auto &info = v.second;
auto it = sels.find(v.first);
auto selected = it==sels.end();
for(auto item : info.items) {
if(selected == item->isSelected()) {
for(auto item : info.items)
item->setSelected(selected);
scroll = info.depItem;
info.depItem->setSelected(selected);
scroll = info.depItem;
if(!selected)
sels.erase(it);
else
sels.insert(v.first);
break;
}
ui->depList->clear();
depMap.clear();
ui->inList->clear();
inMap.clear();
std::vector<App::DocumentObject *> sels;
for (auto item : ui->treeWidget->selectedItems()) {
if (item == allItem) {
sels.clear();
break;
}
auto obj = qvariant_cast<App::SubObjectT>(item->data(0, Qt::UserRole)).getObject();
if (obj)
sels.push_back(obj);
}
std::vector<App::DocumentObject*> _deps;
if (sels.size()) {
std::sort(sels.begin(), sels.end());
for (auto dep : App::Document::getDependencyList(sels, App::Document::DepSort)) {
if (!std::binary_search(sels.begin(), sels.end(), dep))
_deps.push_back(dep);
}
}
if(scroll)
ui->depList->scrollToItem(scroll);
}
void DlgObjectSelection::onDepSelectionChanged() {
SignalBlocker block2(ui->treeWidget);
SignalBlocker block(ui->depList);
QTreeWidgetItem *scroll=nullptr;
for(auto &v : objMap) {
auto &info = v.second;
auto it = sels.find(v.first);
auto selected = it==sels.end();
if(info.depItem->isSelected()==selected) {
for(auto item : info.items) {
scroll = item;
item->setSelected(selected);
}
if(!selected)
sels.erase(it);
else {
sels.insert(v.first);
for(auto item : info.items) {
for(auto parent=item->parent();parent;parent=parent->parent())
parent->setExpanded(true);
}
}
}
bool enabled = ui->depList->isSortingEnabled();
if (enabled)
ui->depList->setSortingEnabled(false);
bool enabled2 = ui->inList->isSortingEnabled();
if (enabled2)
ui->inList->setSortingEnabled(false);
{
QSignalBlocker blocker(ui->depList);
auto &objs = sels.size() ? _deps : deps;
for (auto it = objs.rbegin(); it != objs.rend(); ++it)
createDepItem(ui->depList, *it);
}
if(scroll)
ui->treeWidget->scrollToItem(scroll);
}
void DlgObjectSelection::onUseOriginalsBtnClicked(){
returnOriginals = true;
QDialog::accept();
std::set<App::DocumentObject*> inlist;
for (auto obj : sels)
obj->getInListEx(inlist, true);
for (auto it = inlist.begin(); it != inlist.end();) {
if (!depSet.count(*it) || std::binary_search(sels.begin(), sels.end(), *it))
it = inlist.erase(it);
else
++it;
}
{
QSignalBlocker blocker2(ui->inList);
for (auto obj : inlist)
createDepItem(ui->inList, obj);
}
if (enabled)
ui->depList->setSortingEnabled(true);
if (enabled2)
ui->inList->setSortingEnabled(true);
}
void DlgObjectSelection::accept() {
@@ -391,4 +597,42 @@ void DlgObjectSelection::reject() {
QDialog::reject();
}
void DlgObjectSelection::addCheckBox(QCheckBox *box) {
ui->horizontalLayout->insertWidget(0, box);
}
void DlgObjectSelection::setMessage(const QString &msg) {
ui->label->setText(msg);
}
void DlgObjectSelection::onAutoDeps(bool checked)
{
hGrp->SetBool("ObjectSelectionAutoDeps", checked);
if (!checked)
return;
QSignalBlocker blocker(ui->treeWidget);
for (auto obj : deps) {
auto it = itemMap.find(obj);
if (it == itemMap.end())
continue;
auto item = it->second[0];
if (item->checkState(0) == Qt::Unchecked)
continue;
Qt::CheckState state = Qt::Checked;
for (auto o : obj->getOutList()) {
auto it = itemMap.find(o);
if (it == itemMap.end())
continue;
if (it->second[0]->checkState(0) != Qt::Checked) {
state = Qt::PartiallyChecked;
break;
}
}
for (auto i : it->second)
setCheckState(i, state);
}
onItemSelectionChanged();
}
#include "moc_DlgObjectSelection.cpp"