home | tech | misc | code | bookmarks (broken) | contact | README


FreeCAD Development Notes

Last update to this page was in 2019-02-13.

Tips for debugging

Qt's qDebug() << "foo\n"; just doesn't work here. FreeCAD guys have done a different thing. Instead, you should use:

/* This comes at the top, if there is any error */
#include <PreCompiled.h>
#include <Base/Console.h>

/* this comes where you want the debug output */
Base::Console().Warning("foo\n");

Source code explained (at least a small part of it)

Trying to solve issue 3786 (Ability to cycle between selectable objects (using a keyboard shortcut)

Trying to solve issue 3786 (Ability to cycle between selectable objects (using a keyboard shortcut), we see that most (if not all?) mouse events for the workspace area (I don't know if this is the correct name) are in src/Gui/Quarter/Mouse.cpp. We can see they here:

File src/Gui/Quarter/Mouse.cpp, lines 203 through 219:

switch (event->button()) {
case Qt::LeftButton:
  this->mousebutton->setButton(SoMouseButtonEvent::BUTTON1);
  break;
case Qt::RightButton:
  this->mousebutton->setButton(SoMouseButtonEvent::BUTTON2);
  break;
case Qt::MidButton:
  this->mousebutton->setButton(SoMouseButtonEvent::BUTTON3);
  break;
default:
  this->mousebutton->setButton(SoMouseButtonEvent::ANY);
  SoDebugError::postInfo("Mouse::mouseButtonEvent",
                         "Unhandled ButtonState = %x", event->button());
  break;
}
return this->mousebutton;

This is returned to Mouse::translateEvent(QEvent * event) in the same file:

File src/Gui/Quarter/Mouse.cpp, lines 112 through 136:

/*! Translates from QMouseEvents to SoLocation2Events and
  SoMouseButtonEvents
 */
const SoEvent *
Mouse::translateEvent(QEvent * event)
{
  switch (event->type()) {
  case QEvent::MouseMove:
    return PRIVATE(this)->mouseMoveEvent((QMouseEvent *) event);
  case QEvent::MouseButtonPress:
  case QEvent::MouseButtonRelease:
    // a dblclick event comes in a series of press, release, dblclick,
    // release, so we can simply treat it as an ordinary press event.
    // -mortene.
  case QEvent::MouseButtonDblClick:
    return PRIVATE(this)->mouseButtonEvent((QMouseEvent *) event);
  case QEvent::Wheel:
    return PRIVATE(this)->mouseWheelEvent((QWheelEvent *) event);
  case QEvent::Resize:
    PRIVATE(this)->resizeEvent((QResizeEvent *) event);
    return NULL;
  default:
    return NULL;
  }
}

Who calls this? A quick grep tell us is, in the same directory, EventFilter.cpp, in EventFilter::eventFilter(QObject * obj, QEvent * qevent):

File src/Gui/Quarter/EventFilter.cpp, lines 169 through 176:

// translate QEvent into SoEvent and see if it is handled by scene
// graph
foreach(InputDevice * device, PRIVATE(this)->devices) {
  const SoEvent * soevent = device->translateEvent(qevent);
  if (soevent && PRIVATE(this)->quarterwidget->processSoEvent(soevent)) {
    return true;
  }
}

So, we believe the event is passed to SoQt (a Coin3D interface to Qt). Let's investigate what the function call within the if means. PRIVATE macro is defined here:

File src/Gui/Quarter/EventFilter.cpp, lines 90 through 90:

#define PRIVATE(obj) obj->pimpl

And defined here:

File src/Gui/Quarter/EventFilter.cpp, lines 99 through 103:

PRIVATE(this) = new EventFilterP;

QuarterWidget* quarter = dynamic_cast<QuarterWidget *>(parent);
PRIVATE(this)->quarterwidget = quarter;
assert(PRIVATE(this)->quarterwidget);

QuarterWidget is a big class defined in QuarterWidget.cpp file. Next now locate the processSoEvent() method.

File src/Gui/Quarter/QuarterWidget.cpp, lines 1023 through 1036:

/*!
  Passes an event to the eventmanager.

  \param[in] event to pass
  \retval Returns true if the event was successfully processed
*/
bool
QuarterWidget::processSoEvent(const SoEvent * event)
{
  return
    event &&
    PRIVATE(this)->soeventmanager &&
    PRIVATE(this)->soeventmanager->processEvent(event);
}

soeventmanager is defined here:

File src/Gui/Quarter/EventFilter.cpp, lines 277 through 277:

PRIVATE(this)->soeventmanager = new SoEventManager;

SoEventManager is a class of Coin3D. The documentation of this class is here.

To be continued...