Esempio n. 1
0
static PyObject *
meth_get__doc__(PythonQtSlotFunctionObject * m, void * /*closure*/)
{
  QByteArray doc;
  PythonQtSlotInfo* info = m->m_ml;
  const QByteArray& returnType = info->parameters().at(0).name;
  int returnTypeId = info->parameters().at(0).typeId;

  PythonQtSlotInfo* longestInfo = info;
  PythonQtSlotInfo* infoSearch = info->nextInfo();
  while (infoSearch) {
    if (longestInfo->parameterCount() < infoSearch->parameterCount()) {
      longestInfo = infoSearch;
    }
    infoSearch = infoSearch->nextInfo();
  }
  doc = "X." + info->slotName(true) + "(";
  for (int i = 1;i<longestInfo->parameterCount(); i++) {
    if (i!=1) {
      doc += ", ";
    }
    doc += QString('a' + i-1);
  }
  doc += ")";
  QByteArray pyReturnType;
  if (returnType == "QString" || returnType == "SbName" || returnType == "SbString") {
    pyReturnType = "str";
  } else if (returnType.startsWith("QVector<") || returnType.startsWith("QList<") ||
             returnType == "QStringList" || returnType == "QObjectList" || returnType == "QVariantList") {
    pyReturnType = "tuple";
  } else if (returnType.startsWith("QHash<") || returnType.startsWith("QMap<") ||
    returnType == "QVariantMap" || returnType == "QVariantHash") {
    pyReturnType = "dict";
  } else if (returnTypeId == QVariant::Bool) {
    pyReturnType = "bool";
  } else if (returnTypeId == PythonQtMethodInfo::Variant) {
    pyReturnType = "object";
  } else if (returnTypeId == QMetaType::Char || returnTypeId == QMetaType::UChar ||
    returnTypeId == QMetaType::Short || returnTypeId == QMetaType::UShort ||
    returnTypeId == QMetaType::Int || returnTypeId == QMetaType::UInt ||
    returnTypeId == QMetaType::Long || returnTypeId == QMetaType::ULong ||
    returnTypeId == QMetaType::LongLong || returnTypeId == QMetaType::ULongLong) {
    pyReturnType = "int";
  } else if (returnTypeId == QMetaType::Float || returnTypeId == QMetaType::Double) {
    pyReturnType = "float";
  } else {
    PythonQtClassInfo* returnTypeClassInfo = PythonQt::priv()->getClassInfo(returnType);
    if (returnTypeClassInfo) {
      PyObject* s = PyObject_GetAttrString(returnTypeClassInfo->pythonQtClassWrapper(), "__module__");
      if (s) {
        pyReturnType = QByteArray(PyString_AsString(s)) + "." + returnType;
        Py_DECREF(s);
      }
    }
  }
  if (!pyReturnType.isEmpty()) {
    doc += " -> " + pyReturnType;
  }
  return PyString_FromString(doc.constData());
}
bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer)
{
  static unsigned int recursiveEntry = 0;

  if (directReturnValuePointer) {
    *directReturnValuePointer = NULL;
  }
  // store the current storage position, so that we can get back to this state after a slot is called
  // (do this locally, so that we have all positions on the stack
  PythonQtValueStoragePosition globalValueStoragePos;
  PythonQtValueStoragePosition globalPtrStoragePos;
  PythonQtValueStoragePosition globalVariantStoragePos;
  PythonQtConv::global_valueStorage.getPos(globalValueStoragePos);
  PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos);
  PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos);

  recursiveEntry++;

  // the arguments that are passed to qt_metacall
  void* argList[PYTHONQT_MAX_ARGS];
  PyObject* result = NULL;
  int argc = info->parameterCount();
  const QList<PythonQtSlotInfo::ParameterInfo>& params = info->parameters();

  const PythonQtSlotInfo::ParameterInfo& returnValueParam = params.at(0);
  // set return argument to NULL
  argList[0] = NULL;

  bool ok = true;
  bool skipFirst = false;
  if (info->isInstanceDecorator()) {
    skipFirst = true;

    // for decorators on CPP objects, we take the cpp ptr, for QObjects we take the QObject pointer
    void* arg1 = firstArgument;
    if (!arg1) {
      arg1 = objectToCall;
    }
    if (arg1) {
      // upcast to correct parent class
      arg1 = ((char*)arg1)+info->upcastingOffset();
    }

    argList[1] = &arg1;
    if (ok) {
      for (int i = 2; i<argc && ok; i++) {
        const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
        argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-2), strict, classInfo);
        if (argList[i]==NULL) {
          ok = false;
          break;
        }
      }
    }
  } else {
    for (int i = 1; i<argc && ok; i++) {
      const PythonQtSlotInfo::ParameterInfo& param = params.at(i);
      argList[i] = PythonQtConv::ConvertPythonToQt(param, PyTuple_GET_ITEM(args, i-1), strict, classInfo);
      if (argList[i]==NULL) {
        ok = false;
        break;
      }
    }
  }

  if (ok) {
    // parameters are ok, now create the qt return value which is assigned to by metacall
    if (returnValueParam.typeId != QMetaType::Void) {
      // create empty default value for the return value
      if (!directReturnValuePointer) {
        // create empty default value for the return value
        argList[0] = PythonQtConv::CreateQtReturnValue(returnValueParam);
        if (argList[0]==NULL) {
          // return value could not be created, maybe we have a registered class with a default constructor, so that we can construct the pythonqt wrapper object and
          // pass its internal pointer
          PythonQtClassInfo* info = PythonQt::priv()->getClassInfo(returnValueParam.name);
          if (info && info->pythonQtClassWrapper()) {
            PyObject* emptyTuple = PyTuple_New(0);
            // 1) default construct an empty object as python object (owned by PythonQt), by calling the meta class with empty arguments
            result = PyObject_Call((PyObject*)info->pythonQtClassWrapper(), emptyTuple, NULL);
            if (result) {
              argList[0] = ((PythonQtInstanceWrapper*)result)->_wrappedPtr;
            }
            Py_DECREF(emptyTuple);
          }
        }
      } else {
        // we can use our pointer directly!
        argList[0] = directReturnValuePointer;
      }
    }


    PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB();
    if (profilingCB) {
      const char* className = NULL;
      if (info->decorator()) {
        className = info->decorator()->metaObject()->className();
      } else {
        className = objectToCall->metaObject()->className();
      }

      profilingCB(PythonQt::Enter, className, info->metaMethod()->signature());
    }

    // invoke the slot via metacall
    bool hadException = false;
    QObject* obj = info->decorator()?info->decorator():objectToCall;
    if (!obj) {
      hadException = true;
      PyErr_SetString(PyExc_RuntimeError, "Trying to call a slot on a deleted QObject!");
    } else {
      try {
        obj->qt_metacall(QMetaObject::InvokeMetaMethod, info->slotIndex(), argList);
      } catch (std::bad_alloc & e) {
        hadException = true;
        QByteArray what("std::bad_alloc: ");
        what += e.what();
        PyErr_SetString(PyExc_MemoryError, what.constData());
      } catch (std::runtime_error & e) {
        hadException = true;
        QByteArray what("std::runtime_error: ");
        what += e.what();
        PyErr_SetString(PyExc_RuntimeError, what.constData());
      } catch (std::logic_error & e) {
        hadException = true;
        QByteArray what("std::logic_error: ");
        what += e.what();
        PyErr_SetString(PyExc_RuntimeError, what.constData());
      } catch (std::exception& e) {
        hadException = true;
        QByteArray what("std::exception: ");
        what += e.what();
        PyErr_SetString(PyExc_StandardError, what.constData());
      }
    }
  
    if (profilingCB) {
      profilingCB(PythonQt::Leave, NULL, NULL);
    }

    // handle the return value (which in most cases still needs to be converted to a Python object)
    if (!hadException) {
      if (argList[0] || returnValueParam.typeId == QMetaType::Void) {
        if (directReturnValuePointer) {
          result = NULL;
        } else {
          // the resulting object maybe present already, because we created it above at 1)...
          if (!result) {
            result = PythonQtConv::ConvertQtValueToPython(returnValueParam, argList[0]);
          }
        }
      } else {
        QString e = QString("Called ") + info->fullSignature() + ", return type '" + returnValueParam.name + "' is ignored because it is unknown to PythonQt. Probably you should register it using qRegisterMetaType() or add a default constructor decorator to the class.";
        PyErr_SetString(PyExc_ValueError, e.toLatin1().data());
        result = NULL;
      }
    } else {
      result = NULL;
    }
  }
  recursiveEntry--;

  // reset the parameter storage position to the stored pos to "pop" the parameter stack
  PythonQtConv::global_valueStorage.setPos(globalValueStoragePos);
  PythonQtConv::global_ptrStorage.setPos(globalPtrStoragePos);
  PythonQtConv::global_variantStorage.setPos(globalVariantStoragePos);

  *pythonReturnValue = result;
  // NOTE: it is important to only return here, otherwise the stack will not be popped!!!
  return result || (directReturnValuePointer && *directReturnValuePointer);
}