Fix #3367: view/data pane is unselected

- error in coordination of Tree & QGraphicsScene
  selection logic caused Feature to become
  unselected during update.
This commit is contained in:
wandererfan
2018-03-17 11:06:33 -04:00
committed by wmayer
parent 91a0aff25f
commit 2d4865bb11
8 changed files with 170 additions and 119 deletions

View File

@@ -147,7 +147,7 @@ MDIViewPage::MDIViewPage(ViewProviderPage *pageVp, Gui::Document* doc, QWidget*
// Connect Signals and Slots
QObject::connect(
m_view->scene(), SIGNAL(selectionChanged()),
this , SLOT (selectionChanged())
this , SLOT (sceneSelectionChanged())
);
//get informed by App side about deleted DocumentObjects
@@ -833,6 +833,7 @@ void MDIViewPage::saveSVG(std::string file)
/////////////// Selection Routines ///////////////////
// wf: this is never executed???
// needs a signal from Scene? hoverEvent? Scene does not emit signal for "preselect"
// there is no "preSelect" signal from Gui either.
void MDIViewPage::preSelectionChanged(const QPoint &pos)
{
QObject *obj = QObject::sender();
@@ -892,13 +893,15 @@ void MDIViewPage::preSelectionChanged(const QPoint &pos)
}
}
//flag to prevent selection activity within mdivp
void MDIViewPage::blockSelection(const bool state)
{
isSelectionBlocked = state;
}
void MDIViewPage::clearSelection()
//Set all QGIViews to unselected state
void MDIViewPage::clearSceneSelection()
{
blockSelection(true);
std::vector<QGIView *> views = m_view->getViews();
@@ -913,9 +916,8 @@ void MDIViewPage::clearSelection()
blockSelection(false);
}
//!Update QGVPage's selection based on Selection made outside Drawing Interface
//invoked from VPP
void MDIViewPage::selectFeature(App::DocumentObject *obj, const bool isSelected)
//!Update QGIView's selection state based on Selection made outside Drawing Interface
void MDIViewPage::selectQGIView(App::DocumentObject *obj, const bool isSelected)
{
App::DocumentObject* objCopy = obj;
TechDraw::DrawHatch* hatchObj = dynamic_cast<TechDraw::DrawHatch*>(objCopy);
@@ -932,39 +934,61 @@ void MDIViewPage::selectFeature(App::DocumentObject *obj, const bool isSelected)
blockSelection(false);
}
//! invoked by selection change made in Tree?
// wf: seems redundant? executed, but no real logic.
//! invoked by selection change made in Tree via father MDIView
//really "onTreeSelectionChanged"
void MDIViewPage::onSelectionChanged(const Gui::SelectionChanges& msg)
{
std::vector<Gui::SelectionSingleton::SelObj> selObjs = Gui::Selection().getSelection(msg.pDocName);
if (msg.Type == Gui::SelectionChanges::ClrSelection) {
}
else if (msg.Type == Gui::SelectionChanges::AddSelection ||
msg.Type == Gui::SelectionChanges::RmvSelection) {
//bool add = (msg.Type == Gui::SelectionChanges::AddSelection);
// Check if it is a view object
std::string feat = msg.pObjectName;
std::string sub = msg.pSubName;
}
else if (msg.Type == Gui::SelectionChanges::SetSelection) {
// do nothing here wf: handled by VPP::onSelectionChanged?
clearSceneSelection();
} else if(msg.Type == Gui::SelectionChanges::SetSelection) { //replace entire selection set
clearSceneSelection();
blockSelection(true);
for (auto& so: selObjs){
if (so.pObject->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) {
selectQGIView(so.pObject, true);
}
}
blockSelection(false);
} else {
bool selectState = (msg.Type == Gui::SelectionChanges::AddSelection) ? true : false;
blockSelection(true);
for (auto& so: selObjs){
if (so.pObject->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) {
selectQGIView(so.pObject, selectState);
}
}
blockSelection(false);
}
}
//! update FC Selection from QGraphicsScene selection
//! update Tree Selection from QGraphicsScene selection
//trigged by m_view->scene() signal
void MDIViewPage::selectionChanged()
void MDIViewPage::sceneSelectionChanged()
{
if(isSelectionBlocked) {
return;
return;
}
QList<QGraphicsItem*> selection = m_view->scene()->selectedItems();
bool saveBlock = blockConnection(true); // avoid to be notified by itself
blockSelection(true);
std::vector<Gui::SelectionObject> treeSel = Gui::Selection().getSelectionEx();
QList<QGraphicsItem*> sceneSel = m_view->scene()->selectedItems();
//check if really need to change selection
bool sameSel = compareSelections(treeSel,sceneSel);
if (sameSel) {
return;
}
setTreeToSceneSelect();
}
void MDIViewPage::setTreeToSceneSelect(void)
{
bool saveBlock = blockConnection(true); // block selectionChanged signal from Tree/Observer
blockSelection(true);
Gui::Selection().clearSelection();
for (QList<QGraphicsItem*>::iterator it = selection.begin(); it != selection.end(); ++it) {
QList<QGraphicsItem*> sceneSel = m_view->scene()->selectedItems();
for (QList<QGraphicsItem*>::iterator it = sceneSel.begin(); it != sceneSel.end(); ++it) {
QGIView *itemView = dynamic_cast<QGIView *>(*it);
if(itemView == 0) {
QGIEdge *edge = dynamic_cast<QGIEdge *>(*it);
@@ -1056,7 +1080,7 @@ void MDIViewPage::selectionChanged()
}
const char* name = dimObj->getNameInDocument();
if (!name) { //can happen during undo/redo if Dim is selected???
//Base::Console().Log("INFO - MDIVP::selectionChanged - dimObj name is null!\n");
//Base::Console().Log("INFO - MDIVP::sceneSelectionChanged - dimObj name is null!\n");
continue;
}
@@ -1077,9 +1101,78 @@ void MDIViewPage::selectionChanged()
}
}
blockConnection(saveBlock);
blockSelection(false);
} // end MDIViewPage::selectionChanged()
blockConnection(saveBlock);
}
bool MDIViewPage::compareSelections(std::vector<Gui::SelectionObject>& treeSel,QList<QGraphicsItem*>& sceneSel)
{
bool result = true;
if (treeSel.empty() && sceneSel.empty()) {
return true;
} else if (treeSel.empty() && !sceneSel.empty()) {
return false;
} else if (!treeSel.empty() && sceneSel.empty()) {
return false;
}
int treeCount = 0;
int sceneCount = 0;
int subCount = 0;
int ppCount = 0;
std::vector<std::string> treeNames;
std::vector<std::string> sceneNames;
for (auto& tn: treeSel) {
if (tn.getObject()->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) {
int treeSubs = tn.getSubNames().size();
subCount += treeSubs;
std::string s = tn.getObject()->getNameInDocument();
treeNames.push_back(s);
}
}
std::sort(treeNames.begin(),treeNames.end());
treeCount = treeNames.size();
for (auto& sn:sceneSel){
QGIView *itemView = dynamic_cast<QGIView *>(sn);
if(itemView == 0) {
QGIPrimPath* pp = dynamic_cast<QGIPrimPath*>(sn); //count Vertex/Edge/Face
if (pp != nullptr) {
ppCount++;
}
} else {
std::string s = itemView->getViewNameAsString();
sceneNames.push_back(s);
}
}
std::sort(sceneNames.begin(),sceneNames.end());
sceneCount = sceneNames.size();
//different # of DrawView* vs QGIV*
if (sceneCount != treeCount) {
return false;
}
// even of counts match, have to check that names in scene == names in tree
auto treePtr = treeNames.begin();
for (auto& s: sceneNames){
if (s == (*treePtr)) {
treePtr++;
continue;
} else {
return false;
}
}
//Objects all match, check subs
if (treeCount != ppCount) {
return false;
}
return result;
}
///////////////////end Selection Routines //////////////////////

View File

@@ -55,11 +55,13 @@ public:
MDIViewPage(ViewProviderPage *page, Gui::Document* doc, QWidget* parent = 0);
virtual ~MDIViewPage();
/// Observer message from the Selection
/// Observer message from the Tree Selection mechanism
void onSelectionChanged(const Gui::SelectionChanges& msg);
void preSelectionChanged(const QPoint &pos);
void selectFeature(App::DocumentObject *obj, bool state);
void clearSelection();
/// QGraphicsScene seletion routines
void selectQGIView(App::DocumentObject *obj, bool state);
void clearSceneSelection();
void blockSelection(bool isBlocked);
void attachTemplate(TechDraw::DrawTemplate *obj);
@@ -100,7 +102,7 @@ public Q_SLOTS:
void setRenderer(QAction *action);
void viewAll();
void saveSVG(void);
void selectionChanged();
void sceneSelectionChanged();
protected:
void findMissingViews( const std::vector<App::DocumentObject*> &list, std::vector<App::DocumentObject*> &missing);
@@ -121,6 +123,9 @@ protected:
typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection;
Connection connectDeletedObject;
bool compareSelections(std::vector<Gui::SelectionObject>& treeSel,QList<QGraphicsItem*>& sceneSel);
void setTreeToSceneSelect(void);
private:
QAction *m_nativeAction;
QAction *m_glAction;

View File

@@ -60,6 +60,7 @@
#include "QGCustomClip.h"
#include "QGIViewClip.h"
#include "ViewProviderDrawingView.h"
#include "MDIViewPage.h"
#include <Mod/TechDraw/App/DrawViewClip.h>
#include <Mod/TechDraw/App/DrawProjGroup.h>
@@ -296,6 +297,11 @@ const char * QGIView::getViewName() const
{
return viewName.c_str();
}
const std::string QGIView::getViewNameAsString() const
{
return viewName;
}
TechDraw::DrawView * QGIView::getViewObject() const
{
@@ -481,6 +487,22 @@ Gui::ViewProvider* QGIView::getViewProvider(App::DocumentObject* obj)
return result;
}
MDIViewPage* QGIView::getMDIViewPage(void) const
{
MDIViewPage* result = nullptr;
QGraphicsScene* s = scene();
QObject* parent = nullptr;
if (s != nullptr) {
parent = s->parent();
}
if (parent != nullptr) {
MDIViewPage* mdi = dynamic_cast<MDIViewPage*>(parent);
if (mdi != nullptr) {
result = mdi;
}
}
return result;
}
QColor QGIView::getNormalColor()
{

View File

@@ -46,6 +46,7 @@ class QGCustomBorder;
class QGCustomLabel;
class QGCustomText;
class QGICaption;
class MDIViewPage;
class TechDrawGuiExport QGIView : public QGraphicsItemGroup
{
@@ -61,7 +62,8 @@ public:
const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr ) override;
const char * getViewName() const;
const char * getViewName() const;
const std::string getViewNameAsString() const;
void setViewFeature(TechDraw::DrawView *obj);
TechDraw::DrawView * getViewObject() const;
@@ -92,6 +94,7 @@ public:
virtual QColor getSelectColor(void);
static Gui::ViewProvider* getViewProvider(App::DocumentObject* obj);
MDIViewPage* getMDIViewPage(void) const;
protected:
QGIView* getQGIVByName(std::string name);

View File

@@ -72,6 +72,7 @@
#include "ViewProviderGeomHatch.h"
#include "ViewProviderHatch.h"
#include "ViewProviderViewPart.h"
#include "MDIViewPage.h"
using namespace TechDrawGui;
using namespace TechDrawGeometry;
@@ -99,20 +100,7 @@ QGIViewPart::~QGIViewPart()
QVariant QGIViewPart::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSelectedHasChanged && scene()) {
QList<QGraphicsItem*> items = childItems();
for(QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); ++it) {
//Highlight the children if this is highlighted!? seems to mess up Face selection?
QGIEdge *edge = dynamic_cast<QGIEdge *>(*it);
QGIVertex *vert = dynamic_cast<QGIVertex *>(*it);
QGIFace *face = dynamic_cast<QGIFace *>(*it);
if(edge) {
//edge->setHighlighted(isSelected());
} else if(vert){
//vert->setHighlighted(isSelected());
} else if(face){
//face->setHighlighted(isSelected());
}
}
//There's nothing special for QGIVP to do when selection changes!
} else if(change == ItemSceneChange && scene()) {
tidy();
}
@@ -334,15 +322,6 @@ void QGIViewPart::updateView(bool update)
} else if (update ||
vp->LineWidth.isTouched() ||
vp->HiddenWidth.isTouched()) {
QList<QGraphicsItem*> items = childItems();
for(QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); ++it) {
QGIEdge *edge = dynamic_cast<QGIEdge *>(*it);
if(edge && edge->getHiddenEdge()) {
edge->setWidth(vp->HiddenWidth.getValue() * lineScaleFactor);
} else if (edge){
edge->setWidth(vp->LineWidth.getValue() * lineScaleFactor);
}
}
draw();
} else {
QGIView::draw();
@@ -557,9 +536,14 @@ QGIFace* QGIViewPart::drawFace(TechDrawGeometry::Face* f, int idx)
}
//! Remove all existing QGIPrimPath items(Vertex,Edge,Face)
//note this triggers scene selectionChanged signal if vertex/edge/face is selected
void QGIViewPart::removePrimitives()
{
QList<QGraphicsItem*> children = childItems();
MDIViewPage* mdi = getMDIViewPage();
if (mdi != nullptr) {
getMDIViewPage()->blockSelection(true);
}
for (auto& c:children) {
QGIPrimPath* prim = dynamic_cast<QGIPrimPath*>(c);
if (prim) {
@@ -568,6 +552,9 @@ void QGIViewPart::removePrimitives()
delete prim;
}
}
if (mdi != nullptr) {
getMDIViewPage()->blockSelection(false);
}
}
//! Remove all existing QGIDecoration items(SectionLine,SectionMark,...)

View File

@@ -38,10 +38,12 @@
#endif
#include <App/Application.h>
#include <App/Document.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Stream.h>
#include <Gui/FileDialog.h>
#include <Gui/Selection.h>
#include <Gui/WaitCursor.h>
#include <Mod/TechDraw/App/Geometry.h>

View File

@@ -37,8 +37,6 @@
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/Sequencer.h>
#include <App/Application.h>
#include <App/Document.h>
@@ -46,15 +44,9 @@
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Selection.h>
#include <Gui/ViewProvider.h>
#include <Gui/ViewProviderDocumentObject.h>
#include <Gui/ViewProviderDocumentObjectGroup.h>
#include "MDIViewPage.h"
#include "ViewProviderPage.h"
@@ -291,50 +283,6 @@ MDIViewPage* ViewProviderPage::getMDIViewPage()
}
}
void ViewProviderPage::onSelectionChanged(const Gui::SelectionChanges& msg)
{
if(!m_mdiView.isNull()) {
if(msg.Type == Gui::SelectionChanges::SetSelection) {
m_mdiView->clearSelection();
std::vector<Gui::SelectionSingleton::SelObj> objs = Gui::Selection().getSelection(msg.pDocName);
for (std::vector<Gui::SelectionSingleton::SelObj>::iterator it = objs.begin(); it != objs.end(); ++it) {
Gui::SelectionSingleton::SelObj selObj = *it;
if(selObj.pObject == getDrawPage())
continue;
std::string str = msg.pSubName;
// If it's a subfeature, don't select feature
if (!str.empty()) {
if (TechDraw::DrawUtil::getGeomTypeFromName(str) == "Face" ||
TechDraw::DrawUtil::getGeomTypeFromName(str) == "Edge" ||
TechDraw::DrawUtil::getGeomTypeFromName(str) == "Vertex") {
// TODO implement me wf: don't think this is ever executed
}
} else {
m_mdiView->selectFeature(selObj.pObject, true);
}
}
} else {
bool selectState = (msg.Type == Gui::SelectionChanges::AddSelection) ? true : false;
Gui::Document* doc = Gui::Application::Instance->getDocument(pcObject->getDocument());
App::DocumentObject *obj = doc->getDocument()->getObject(msg.pObjectName);
if(obj) {
std::string str = msg.pSubName;
// If it's a subfeature, don't select feature
if (!str.empty()) {
if (TechDraw::DrawUtil::getGeomTypeFromName(str) == "Face" ||
TechDraw::DrawUtil::getGeomTypeFromName(str) == "Edge" ||
TechDraw::DrawUtil::getGeomTypeFromName(str) == "Vertex") {
// TODO implement me
} else {
m_mdiView->selectFeature(obj, selectState);
}
}
}
} //else (Gui::SelectionChanges::SetPreselect)
}
}
void ViewProviderPage::onChanged(const App::Property *prop)
{

View File

@@ -26,9 +26,7 @@
#define DRAWINGGUI_VIEWPROVIDERPAGE_H
#include <QPointer>
#include <Gui/ViewProviderFeature.h>
#include <Gui/ViewProviderDocumentObjectGroup.h>
#include <Gui/Selection.h>
#include <Gui/ViewProviderDocumentObject.h>
namespace TechDraw{
class DrawPage;
@@ -38,8 +36,7 @@ namespace TechDrawGui {
class MDIViewPage;
class TechDrawGuiExport ViewProviderPage : public Gui::ViewProviderDocumentObject,
public Gui::SelectionObserver
class TechDrawGuiExport ViewProviderPage : public Gui::ViewProviderDocumentObject
{
PROPERTY_HEADER(TechDrawGui::ViewProviderPage);
@@ -49,10 +46,6 @@ public:
/// destructor
virtual ~ViewProviderPage();
//App::PropertyFloat HintScale;
//App::PropertyFloat HintOffsetX;
//App::PropertyFloat HintOffsetY;
virtual void attach(App::DocumentObject *);
virtual void setDisplayMode(const char* ModeName);
virtual bool useNewSelectionModel(void) const {return false;}
@@ -64,8 +57,6 @@ public:
virtual void show(void);
virtual bool isShow(void) const;
void onSelectionChanged(const Gui::SelectionChanges& msg);
/// Claim all the views for the page
std::vector<App::DocumentObject*> claimChildren(void) const;