//*****************************************************************************************************
// Document
//*****************************************************************************************************
void Document::slotNewObject(const App::DocumentObject& Obj)
{
    //Base::Console().Log("Document::slotNewObject() called\n");
    std::string cName = Obj.getViewProviderName();
    if (cName.empty()) {
        // handle document object with no view provider specified
        Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName());
        return;
    }
  
    setModified(true);
    Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(cName.c_str(),true));
    if (base) {
        // type not derived from ViewProviderDocumentObject!!!
        assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()));
        ViewProviderDocumentObject *pcProvider = static_cast<ViewProviderDocumentObject*>(base);
        d->_ViewProviderMap[&Obj] = pcProvider;

        try {
            // if succesfully created set the right name and calculate the view
            //FIXME: Consider to change argument of attach() to const pointer
            pcProvider->attach(const_cast<App::DocumentObject*>(&Obj));
            pcProvider->updateView();
            pcProvider->setActiveMode();
        }
        catch(const Base::MemoryException& e){
            Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
        }
        catch(Base::Exception &e){
            e.ReportException();
        }
#ifndef FC_DEBUG
        catch(...){
            Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument());
        }
#endif

        std::list<Gui::BaseView*>::iterator vIt;
        // cycling to all views of the document
        for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
            View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
            if (activeView)
                activeView->getViewer()->addViewProvider(pcProvider);
        }
    
        // adding to the tree
        signalNewObject(*pcProvider);
    }
    else {
        Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str());
    }
}
void ActiveObjectList::objectDeleted(const ViewProviderDocumentObject& viewProviderIn)
{
  App::DocumentObject* object = viewProviderIn.getObject();
  //maybe boost::bimap or boost::multi_index
  std::map<std::string, App::DocumentObject*>::iterator it;
  for (it = _ObjectMap.begin(); it != _ObjectMap.end(); ++it)
  {
    if (it->second == object)
    {
      _ObjectMap.erase(it);
      return;
    }
  }
}
// doc from parent
void
SoFCUnifiedSelection::handleEvent(SoHandleEventAction * action)
{
    // If off then don't handle this event
    if (!selectionRole.getValue()) {
        inherited::handleEvent(action);
        return;
    }

    static char buf[513];
    HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
    const SoEvent * event = action->getEvent();

    // If we don't need to pick for locate highlighting,
    // then just behave as separator and return.
    // NOTE: we still have to pick for ON even though we don't have
    // to re-render, because the app needs to be notified as the mouse
    // goes over locate highlight nodes.
    //if (highlightMode.getValue() == OFF) {
    //    inherited::handleEvent( action );
    //    return;
    //}

    
    //
    // If this is a mouseMotion event, then check for locate highlighting
    //
    if (event->isOfType(SoLocation2Event::getClassTypeId())) {
        // NOTE: If preselection is off then we do not check for a picked point because otherwise this search may slow
        // down extremely the system on really big data sets. In this case we just check for a picked point if the data
        // set has been selected.
        if (mymode == AUTO || mymode == ON) {
            // check to see if the mouse is over our geometry...
            const SoPickedPoint * pp = this->getPickedPoint(action);
            SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
            ViewProvider *vp = 0;
            ViewProviderDocumentObject* vpd = 0;
            if (pPath && pPath->containsPath(action->getCurPath()))
                vp = viewer->getViewProviderByPathFromTail(pPath);
            if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
                vpd = static_cast<ViewProviderDocumentObject*>(vp);

            SbBool old_state = highlighted;
            highlighted = FALSE;
            if (vpd && vpd->useNewSelectionModel() && vpd->isSelectable()) {
                std::string documentName = vpd->getObject()->getDocument()->getName();
                std::string objectName = vpd->getObject()->getNameInDocument();
                std::string subElementName = vpd->getElement(pp ? pp->getDetail() : 0);

                static char buf[513];
                snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                           ,objectName.c_str()
                                           ,subElementName.c_str()
                                           ,pp->getPoint()[0]
                                           ,pp->getPoint()[1]
                                           ,pp->getPoint()[2]);

                getMainWindow()->showMessage(QString::fromAscii(buf),3000);

                if (Gui::Selection().setPreselect(documentName.c_str()
                                       ,objectName.c_str()
                                       ,subElementName.c_str()
                                       ,pp->getPoint()[0]
                                       ,pp->getPoint()[1]
                                       ,pp->getPoint()[2])){

                    SoSearchAction sa;
                    sa.setNode(vp->getRoot());
                    sa.apply(vp->getRoot());
                    if (sa.getPath()) {
                        highlighted = TRUE;
                        if (currenthighlight && currenthighlight->getTail() != sa.getPath()->getTail()) {
                            SoHighlightElementAction action;
                            action.setHighlighted(FALSE);
                            action.apply(currenthighlight);
                            currenthighlight->unref();
                            currenthighlight = 0;
                            old_state = !highlighted;
                        }

                        currenthighlight = static_cast<SoFullPath*>(sa.getPath()->copy());
                        currenthighlight->ref();
                    }
                }
            }

            if (currenthighlight/* && old_state != highlighted*/) {
                SoHighlightElementAction action;
                action.setHighlighted(highlighted);
                action.setColor(this->colorHighlight.getValue());
                action.setElement(pp ? pp->getDetail() : 0);
                action.apply(currenthighlight);
                if (!highlighted) {
                    currenthighlight->unref();
                    currenthighlight = 0;
                }
                this->touch();
            }
        }
    }
    // key press events
    else if (event->isOfType(SoKeyboardEvent ::getClassTypeId())) {
        SoKeyboardEvent  * const e = (SoKeyboardEvent  *) event;
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_SHIFT)     ||
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_SHIFT)     )
            bShift = true;
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_SHIFT)   ||
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_SHIFT)   )
            bShift = false;
        if (SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::LEFT_CONTROL)   ||
            SoKeyboardEvent::isKeyPressEvent(e,SoKeyboardEvent::RIGHT_CONTROL)   )
            bCtrl = true;
        if (SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::LEFT_CONTROL) ||
            SoKeyboardEvent::isKeyReleaseEvent(e,SoKeyboardEvent::RIGHT_CONTROL) )
            bCtrl = false;
    }
    // mouse press events for (de)selection
    else if (event->isOfType(SoMouseButtonEvent::getClassTypeId()) && 
             selectionMode.getValue() == SoFCUnifiedSelection::ON) {
        const SoMouseButtonEvent* e = static_cast<const SoMouseButtonEvent *>(event);
        if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
            // check to see if the mouse is over a geometry...
            const SoPickedPoint * pp = this->getPickedPoint(action);
            SoFullPath *pPath = (pp != NULL) ? (SoFullPath *) pp->getPath() : NULL;
            ViewProvider *vp = 0;
            ViewProviderDocumentObject* vpd = 0;
            if (pPath && pPath->containsPath(action->getCurPath()))
                vp = viewer->getViewProviderByPathFromTail(pPath);
            if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
                vpd = static_cast<ViewProviderDocumentObject*>(vp);
            if (vpd && vpd->useNewSelectionModel() && vpd->isSelectable()) {
                SoSelectionElementAction::Type type = SoSelectionElementAction::None;
                std::string documentName = vpd->getObject()->getDocument()->getName();
                std::string objectName = vpd->getObject()->getNameInDocument();
                std::string subElementName = vpd->getElement(pp ? pp->getDetail() : 0);
                if (bCtrl) {
                    if (Gui::Selection().isSelected(documentName.c_str()
                                         ,objectName.c_str()
                                         ,subElementName.c_str())) {
                        Gui::Selection().rmvSelection(documentName.c_str()
                                          ,objectName.c_str()
                                          ,subElementName.c_str());
                        type = SoSelectionElementAction::Remove;
                    }
                    else {
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                          ,objectName.c_str()
                                          ,subElementName.c_str()
                                          ,pp->getPoint()[0]
                                          ,pp->getPoint()[1]
                                          ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::Append;
                        if (mymode == OFF) {
                            snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                                       ,objectName.c_str()
                                                       ,subElementName.c_str()
                                                       ,pp->getPoint()[0]
                                                       ,pp->getPoint()[1]
                                                       ,pp->getPoint()[2]);

                            getMainWindow()->showMessage(QString::fromAscii(buf),3000);
                        }
                    }
                }
                else { // Ctrl
                    if (!Gui::Selection().isSelected(documentName.c_str()
                                         ,objectName.c_str()
                                         ,subElementName.c_str())) {
                        Gui::Selection().clearSelection(documentName.c_str());
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                              ,objectName.c_str()
                                              ,subElementName.c_str()
                                              ,pp->getPoint()[0]
                                              ,pp->getPoint()[1]
                                              ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::Append;
                    }
                    else {
                        Gui::Selection().clearSelection(documentName.c_str());
                        bool ok = Gui::Selection().addSelection(documentName.c_str()
                                              ,objectName.c_str()
                                              ,0
                                              ,pp->getPoint()[0]
                                              ,pp->getPoint()[1]
                                              ,pp->getPoint()[2]);
                        if (ok)
                            type = SoSelectionElementAction::All;
                    }

                    if (mymode == OFF) {
                        snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.c_str()
                                                   ,objectName.c_str()
                                                   ,subElementName.c_str()
                                                   ,pp->getPoint()[0]
                                                   ,pp->getPoint()[1]
                                                   ,pp->getPoint()[2]);

                        getMainWindow()->showMessage(QString::fromAscii(buf),3000);
                    }
                }

                action->setHandled(); 
                if (currenthighlight) {
                    SoSelectionElementAction action(type);
                    action.setColor(this->colorSelection.getValue());
                    action.setElement(pp ? pp->getDetail() : 0);
                    action.apply(currenthighlight);
                    this->touch();
                }
            } // picked point
        } // mouse release
    }

    inherited::handleEvent(action);
}
void SoFCUnifiedSelection::doAction(SoAction *action)
{
    if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
        SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
        if (preaction->highlight) {
            this->highlightMode = SoFCUnifiedSelection::AUTO;
        }
        else {
            this->highlightMode = SoFCUnifiedSelection::OFF;
        }
    }

    if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
        SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
        if (selaction->selection) {
            this->selectionMode = SoFCUnifiedSelection::ON;
        }
        else {
            this->selectionMode = SoFCUnifiedSelection::OFF;
        }
    }

    if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
        SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
        this->colorSelection = colaction->selectionColor;
    }

    if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
        SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
        this->colorHighlight = colaction->highlightColor;
    }

    if (selectionMode.getValue() == ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
        SoFCSelectionAction *selaction = static_cast<SoFCSelectionAction*>(action);
        if (selaction->SelChange.Type == SelectionChanges::AddSelection || 
            selaction->SelChange.Type == SelectionChanges::RmvSelection) {
            // selection changes inside the 3d view are handled in handleEvent()
            if (!currenthighlight) {
                App::Document* doc = App::GetApplication().getDocument(selaction->SelChange.pDocName);
                App::DocumentObject* obj = doc->getObject(selaction->SelChange.pObjectName);
                ViewProvider*vp = Application::Instance->getViewProvider(obj);
                if (vp && vp->useNewSelectionModel() && vp->isSelectable()) {
                    SoDetail* detail = vp->getDetail(selaction->SelChange.pSubName);
                    SoSelectionElementAction::Type type = SoSelectionElementAction::None;
                    if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
                        if (detail)
                            type = SoSelectionElementAction::Append;
                        else
                            type = SoSelectionElementAction::All;
                    }
                    else {
                        if (detail)
                            type = SoSelectionElementAction::Remove;
                        else
                            type = SoSelectionElementAction::None;
                    }

                    SoSelectionElementAction action(type);
                    action.setColor(this->colorSelection.getValue());
                    action.setElement(detail);
                    action.apply(vp->getRoot());
                    delete detail;
                }
            }
        }
        else if (selaction->SelChange.Type == SelectionChanges::ClrSelection ||
                 selaction->SelChange.Type == SelectionChanges::SetSelection) {
            std::vector<ViewProvider*> vps = this->viewer->getViewProvidersOfType
                (ViewProviderDocumentObject::getClassTypeId());
            for (std::vector<ViewProvider*>::iterator it = vps.begin(); it != vps.end(); ++it) {
                ViewProviderDocumentObject* vpd = static_cast<ViewProviderDocumentObject*>(*it);
                if (vpd->useNewSelectionModel()) {
                    if (Selection().isSelected(vpd->getObject()) && vpd->isSelectable()) {
                        SoSelectionElementAction action(SoSelectionElementAction::All);
                        action.setColor(this->colorSelection.getValue());
                        action.apply(vpd->getRoot());
                    }
                    else {
                        SoSelectionElementAction action(SoSelectionElementAction::None);
                        action.setColor(this->colorSelection.getValue());
                        action.apply(vpd->getRoot());
                    }
                }
            }
        }
    }

    inherited::doAction( action );
}