Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jose Luis Cercos Pita 2015-10-20 10:53:52 +02:00
commit c16c27cd0e
68 changed files with 886 additions and 685 deletions

View File

@ -160,7 +160,7 @@ Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform()
static Standard_Real readFloat(OSD_File& theFile)
{
union {
Standard_Boolean i;
Standard_Integer i;
Standard_ShortReal f;
}u;

View File

@ -54,6 +54,10 @@
#include <Standard_ErrorHandler.hxx>
// Netgen include files
#ifdef _MSC_VER
#pragma warning(disable : 4067)
#endif
namespace nglib {
#include <nglib.h>
}

View File

@ -50,6 +50,10 @@
/*
Netgen include files
*/
#ifdef _MSC_VER
#pragma warning(disable : 4067)
#endif
namespace nglib {
#include <nglib.h>
}

View File

@ -59,6 +59,9 @@
/*
Netgen include files
*/
#ifdef _MSC_VER
#pragma warning(disable : 4067)
#endif
namespace nglib {
#include <nglib.h>

View File

@ -63,6 +63,8 @@
#if defined(_MSC_VER)
#define strtoll _strtoi64
#pragma warning(disable : 4003)
#pragma warning(disable : 4065)
#endif
using namespace Base;

View File

@ -706,8 +706,23 @@ void Application::slotActiveDocument(const App::Document& Doc)
{
std::map<const App::Document*, Gui::Document*>::iterator doc = d->documents.find(&Doc);
// this can happen when closing a document with two views opened
if (doc != d->documents.end())
if (doc != d->documents.end()) {
// this can happen when calling App.setActiveDocument directly from Python
// because no MDI view will be activated
if (d->activeDocument != doc->second) {
d->activeDocument = doc->second;
if (d->activeDocument) {
Base::PyGILStateLocker lock;
Py::Object active(d->activeDocument->getPyObject(), true);
Py::Module("FreeCADGui").setAttr(std::string("ActiveDocument"),active);
}
else {
Base::PyGILStateLocker lock;
Py::Module("FreeCADGui").setAttr(std::string("ActiveDocument"),Py::None());
}
}
signalActiveDocument(*doc->second);
}
}
void Application::slotNewObject(const ViewProvider& vp)

View File

@ -231,6 +231,7 @@ public:
PYFUNCDEF_S(sExport);
PYFUNCDEF_S(sActiveDocument);
PYFUNCDEF_S(sSetActiveDocument);
PYFUNCDEF_S(sGetDocument);
PYFUNCDEF_S(sDoCommand);

View File

@ -54,6 +54,7 @@
#include "Language/Translator.h"
#include "DownloadManager.h"
#include <App/DocumentObjectPy.h>
#include <App/DocumentPy.h>
#include <App/PropertyFile.h>
#include <Base/Interpreter.h>
#include <Base/Console.h>
@ -139,6 +140,9 @@ PyMethodDef Application::Methods[] = {
{"activeDocument", (PyCFunction) Application::sActiveDocument, 1,
"activeDocument() -> object or None\n\n"
"Return the active document or None if no one exists"},
{"setActiveDocument", (PyCFunction) Application::sSetActiveDocument,1,
"setActiveDocument(string or App.Document) -> None\n\n"
"Activate the specified document"},
{"getDocument", (PyCFunction) Application::sGetDocument, 1,
"getDocument(string) -> object\n\n"
"Get a document by its name"},
@ -171,19 +175,71 @@ PyObject* Gui::Application::sActiveDocument(PyObject * /*self*/, PyObject *args,
}
}
PyObject* Application::sGetDocument(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
PyObject* Gui::Application::sSetActiveDocument(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
{
char *pstr=0;
if (!PyArg_ParseTuple(args, "s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
Document *pcDoc = 0;
do {
char *pstr=0;
if (PyArg_ParseTuple(args, "s", &pstr)) {
pcDoc = Instance->getDocument(pstr);
if (!pcDoc) {
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
return 0;
}
break;
}
PyErr_Clear();
PyObject* doc;
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
pcDoc = Instance->getDocument(static_cast<App::DocumentPy*>(doc)->getDocumentPtr());
if (!pcDoc) {
PyErr_Format(PyExc_KeyError, "Unknown document instance");
return 0;
}
break;
}
}
while(false);
Document *pcDoc = Instance->getDocument(pstr);
if (!pcDoc) {
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
PyErr_SetString(PyExc_TypeError, "Either string or App.Document expected");
return 0;
}
return pcDoc->getPyObject();
if (Instance->activeDocument() != pcDoc) {
Gui::MDIView* view = pcDoc->getActiveView();
getMainWindow()->setActiveWindow(view);
}
Py_Return;
}
PyObject* Application::sGetDocument(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
{
char *pstr=0;
if (PyArg_ParseTuple(args, "s", &pstr)) {
Document *pcDoc = Instance->getDocument(pstr);
if (!pcDoc) {
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
return 0;
}
return pcDoc->getPyObject();
}
PyErr_Clear();
PyObject* doc;
if (PyArg_ParseTuple(args, "O!", &(App::DocumentPy::Type), &doc)) {
Document *pcDoc = Instance->getDocument(static_cast<App::DocumentPy*>(doc)->getDocumentPtr());
if (!pcDoc) {
PyErr_Format(PyExc_KeyError, "Unknown document instance");
return 0;
}
return pcDoc->getPyObject();
}
PyErr_SetString(PyExc_TypeError, "Either string or App.Document exprected");
return 0;
}
PyObject* Application::sHide(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)

View File

@ -213,7 +213,9 @@ void DlgExpressionInput::mousePressEvent(QMouseEvent* ev)
#endif
//we need to reject the dialog when clicked on the background. As the background is transparent
//this is the expected behaviour for the user
this->reject();
bool on = ui->expression->completerActive();
if (!on)
this->reject();
}
void DlgExpressionInput::showEvent(QShowEvent* ev)
@ -240,8 +242,12 @@ bool DlgExpressionInput::eventFilter(QObject *obj, QEvent *ev)
// on the size of the widget. Instead, it must be checked if the
// cursor is on this or an underlying widget or outside.
if (!underMouse()) {
qApp->removeEventFilter(this);
reject();
bool on = ui->expression->completerActive();
// Do this only if the completer is not shown
if (!on) {
qApp->removeEventFilter(this);
reject();
}
}
}

View File

@ -111,12 +111,7 @@ PyObject* DocumentPy::setEdit(PyObject *args)
}
bool ok = getDocumentPtr()->setEdit(getDocumentPtr()->getViewProvider(obj),mod);
if (!ok) {
PyErr_Format(Base::BaseExceptionFreeCADError, "Failed to set object '%s' in edit mode", psFeatStr);
return 0;
}
Py_Return;
return PyBool_FromLong(ok ? 1 : 0);
}
PyObject* DocumentPy::getInEdit(PyObject *args)

View File

@ -25,6 +25,7 @@
#ifndef _PreComp_
# include <QApplication>
# include <QButtonGroup>
# include <QCompleter>
# include <QComboBox>
# include <QDesktopServices>
# include <QGridLayout>
@ -521,7 +522,14 @@ FileChooser::FileChooser ( QWidget * parent )
layout->setMargin( 0 );
layout->setSpacing( 6 );
lineEdit = new QLineEdit( this );
lineEdit = new QLineEdit ( this );
completer = new QCompleter ( this );
completer->setMaxVisibleItems( 12 );
fs_model = new QFileSystemModel( completer );
fs_model->setRootPath(QString::fromUtf8(""));
completer->setModel( fs_model );
lineEdit->setCompleter( completer );
layout->addWidget( lineEdit );
connect(lineEdit, SIGNAL(textChanged(const QString &)),

View File

@ -26,6 +26,8 @@
#include <QFileDialog>
#include <QFileIconProvider>
#include <QFileSystemModel>
#include <QCompleter>
class QButtonGroup;
class QGridLayout;
@ -177,6 +179,8 @@ private Q_SLOTS:
private:
QLineEdit *lineEdit;
QCompleter *completer;
QFileSystemModel *fs_model;
QPushButton *button;
Mode md;
QString _filter;

View File

@ -30,6 +30,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <Quarter/devices/InputDevice.h>
#include <QtGui/QInputEvent>
#include <Inventor/events/SoEvents.h>

View File

@ -38,6 +38,10 @@
*/
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <Quarter/devices/Keyboard.h>
#include <QtCore/QEvent>

View File

@ -37,6 +37,10 @@
QuarterWidget.
*/
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <Quarter/devices/Mouse.h>
#include <QtCore/QEvent>

View File

@ -48,6 +48,10 @@
\endcode
*/
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <assert.h>
#include <QtCore/QEvent>

View File

@ -34,6 +34,10 @@
#include <Quarter/QuarterWidget.h>
#include <Quarter/eventhandlers/EventFilter.h>
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <QtGui/QApplication>
#include <QtGui/QCursor>
#include <QtGui/QMenu>

View File

@ -30,6 +30,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/
#ifdef _MSC_VER
#pragma warning(disable : 4267)
#endif
#include <Quarter/devices/SpaceNavigatorDevice.h>
#include <QtGui/QApplication>

View File

@ -989,7 +989,9 @@ PyMethodDef SelectionSingleton::Methods[] = {
{"getSelection", (PyCFunction) SelectionSingleton::sGetSelection, 1,
"getSelection([string]) -- Return a list of selected objets\n"
"Return a list of selected objects for a given document name. If no\n"
"document is given the complete selection is returned."},
"document name is given the selection for the active document is returned."},
{"getCompleteSelection", (PyCFunction) SelectionSingleton::sGetCompleteSelection, 1,
"getCompleteSelection() -- Return a list of selected objects of all documents."},
{"getSelectionEx", (PyCFunction) SelectionSingleton::sGetSelectionEx, 1,
"getSelectionEx([string]) -- Return a list of SelectionObjects\n"
"Return a list of SelectionObjects for a given document name. If no\n"
@ -1107,10 +1109,27 @@ PyObject *SelectionSingleton::sGetSelection(PyObject * /*self*/, PyObject *args,
return NULL; // NULL triggers exception
std::vector<SelectionSingleton::SelObj> sel;
if (documentName)
sel = Selection().getSelection(documentName);
else
sel = Selection().getCompleteSelection();
sel = Selection().getSelection(documentName);
try {
Py::List list;
for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
list.append(Py::asObject(it->pObject->getPyObject()));
}
return Py::new_reference_to(list);
}
catch (Py::Exception&) {
return 0;
}
}
PyObject *SelectionSingleton::sGetCompleteSelection(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
return NULL; // NULL triggers exception
std::vector<SelectionSingleton::SelObj> sel;
sel = Selection().getCompleteSelection();
try {
Py::List list;

View File

@ -311,6 +311,7 @@ protected:
static PyObject *sIsSelected (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sCountObjectsOfType (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetSelection (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetCompleteSelection(PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetSelectionEx (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetSelectionObject (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sAddSelObserver (PyObject *self,PyObject *args,PyObject *kwd);

View File

@ -36,6 +36,7 @@
# include <QGLFormat>
# include <QGLWidget>
# include <QGLPixelBuffer>
# include <QMessageBox>
# include <QPainter>
# include <QPrinter>
# include <QPrintDialog>
@ -531,6 +532,13 @@ void View3DInventor::print(QPrinter* printer)
#else
QImage img;
QPainter p(printer);
if (!p.isActive() && !printer->outputFileName().isEmpty()) {
qApp->setOverrideCursor(Qt::ArrowCursor);
QMessageBox::critical(this, tr("Opening file failed"),
tr("Can't open file '%1' for writing.").arg(printer->outputFileName()));
qApp->restoreOverrideCursor();
return;
}
QRect rect = printer->pageRect();
bool pbuffer = QGLPixelBuffer::hasOpenGLPbuffers();

View File

@ -2151,6 +2151,7 @@ QVariant PropertyPathItem::toolTip(const App::Property* prop) const
QWidget* PropertyPathItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
Gui::FileChooser *fc = new Gui::FileChooser(parent);
fc->setMode(FileChooser::Directory);
fc->setAutoFillBackground(true);
QObject::connect(fc, SIGNAL(fileNameSelected(const QString&)), receiver, method);
return fc;

View File

@ -422,11 +422,12 @@ def formatObject(target,origin=None):
for p in matchrep.PropertiesList:
if not p in ["DisplayMode","BoundingBox","Proxy","RootNode","Visibility"]:
if p in obrep.PropertiesList:
if hasattr(getattr(matchrep,p),"Value"):
val = getattr(matchrep,p).Value
else:
val = getattr(matchrep,p)
setattr(obrep,p,val)
if not obrep.getEditorMode(p):
if hasattr(getattr(matchrep,p),"Value"):
val = getattr(matchrep,p).Value
else:
val = getattr(matchrep,p)
setattr(obrep,p,val)
if matchrep.DisplayMode in obrep.listDisplayModes():
obrep.DisplayMode = matchrep.DisplayMode
if hasattr(matchrep,"DiffuseColor") and hasattr(obrep,"DiffuseColor"):
@ -998,13 +999,14 @@ def makeCopy(obj,force=None,reparent=False):
for p in obj.PropertiesList:
if not p in ["Proxy"]:
if p in newobj.PropertiesList:
try:
setattr(newobj,p,obj.getPropertyByName(p))
except AttributeError:
if not newobj.getEditorMode(p):
try:
setattr(newobj,p,obj.getPropertyByName(p).Value)
setattr(newobj,p,obj.getPropertyByName(p))
except AttributeError:
pass
try:
setattr(newobj,p,obj.getPropertyByName(p).Value)
except AttributeError:
pass
if reparent:
parents = obj.InList
if parents:

View File

@ -593,6 +593,13 @@ void DrawingView::print(QPrinter* printer)
}
QPainter p(printer);
if (!p.isActive() && !printer->outputFileName().isEmpty()) {
qApp->setOverrideCursor(Qt::ArrowCursor);
QMessageBox::critical(this, tr("Opening file failed"),
tr("Can't open file '%1' for writing.").arg(printer->outputFileName()));
qApp->restoreOverrideCursor();
return;
}
QRect rect = printer->paperRect();
#ifdef Q_OS_WIN32
// On Windows the preview looks broken when using paperRect as render area.

View File

@ -118,6 +118,7 @@ void AppFemExport initFem()
Fem::FemAnalysis ::init();
Fem::FemAnalysisPython ::init();
Fem::FeaturePython ::init();
Fem::FemMesh ::init();
Fem::FemMeshObject ::init();
Fem::FemMeshShapeObject ::init();

View File

@ -88,7 +88,6 @@ SET(FemScripts_SRCS
_ViewProviderFemAnalysis.py
_FemAnalysis.py
_CommandMechanicalShowResult.py
_CommandFrequencyAnalysis.py
_CommandQuickAnalysis.py
_CommandPurgeFemResults.py
_CommandMechanicalJobControl.py

View File

@ -28,6 +28,7 @@
#include "FemAnalysis.h"
#include <App/DocumentObjectPy.h>
#include <App/FeaturePythonPyImp.h>
#include <Base/Placement.h>
#include <Base/Uuid.h>
@ -88,4 +89,24 @@ template<> const char* Fem::FemAnalysisPython::getViewProviderName(void) const {
// explicit template instantiation
template class AppFemExport FeaturePythonT<Fem::FemAnalysis>;
}
}
// ---------------------------------------------------------
namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(Fem::FeaturePython, App::DocumentObject)
template<> const char* Fem::FeaturePython::getViewProviderName(void) const {
return "Gui::ViewProviderPythonFeature";
}
template<> PyObject* Fem::FeaturePython::getPyObject(void) {
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new App::FeaturePythonPyT<App::DocumentObjectPy>(this),true);
}
return Py::new_reference_to(PythonObject);
}
// explicit template instantiation
template class AppFemExport FeaturePythonT<App::DocumentObject>;
/// @endcond
}

View File

@ -65,6 +65,7 @@ protected:
};
typedef App::FeaturePythonT<FemAnalysis> FemAnalysisPython;
typedef App::FeaturePythonT<App::DocumentObject> FeaturePython;
} //namespace Fem

View File

@ -911,7 +911,12 @@ void FemMesh::writeABAQUS(const std::string &Filename) const
std::ofstream anABAQUS_Output;
anABAQUS_Output.open(Filename.c_str());
// add nodes
//
anABAQUS_Output << "*Node, NSET=Nall" << std::endl;
typedef std::map<int, Base::Vector3d> VertexMap;
VertexMap vertexMap;
//Extract Nodes and Elements of the current SMESH datastructure
SMDS_NodeIteratorPtr aNodeIter = myMesh->GetMeshDS()->nodesIterator();
@ -921,10 +926,16 @@ void FemMesh::writeABAQUS(const std::string &Filename) const
const SMDS_MeshNode* aNode = aNodeIter->next();
current_node.Set(aNode->X(),aNode->Y(),aNode->Z());
current_node = _Mtrx * current_node;
anABAQUS_Output << aNode->GetID() << ", "
<< current_node.x << ", "
<< current_node.y << ", "
<< current_node.z << std::endl;
vertexMap[aNode->GetID()] = current_node;
}
// This way we get sorted output.
// See http://forum.freecadweb.org/viewtopic.php?f=18&t=12646&start=40#p103004
for (VertexMap::iterator it = vertexMap.begin(); it != vertexMap.end(); ++it) {
anABAQUS_Output << it->first << ", "
<< it->second.x << ", "
<< it->second.y << ", "
<< it->second.z << std::endl;
}
typedef std::map<int, std::vector<int> > NodesMap;

View File

@ -30,7 +30,6 @@ INSTALL(
_ViewProviderFemAnalysis.py
_FemAnalysis.py
_CommandMechanicalShowResult.py
_CommandFrequencyAnalysis.py
_CommandQuickAnalysis.py
_CommandPurgeFemResults.py
_CommandMechanicalJobControl.py

View File

@ -37,7 +37,7 @@ __url__ = "http://www.freecadweb.org"
def makeFemBeamSection(width=20.0, height=20.0, name="BeamSection"):
'''makeFemBeamSection([width], [height], [name]): creates an beamsection object to define a cross section'''
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", name)
obj = FemGui.getActiveAnalysis().Document.addObject("Fem::FeaturePython", name)
_FemBeamSection(obj)
obj.Width = width
obj.Height = height
@ -57,8 +57,7 @@ class _CommandFemBeamSection:
def Activated(self):
FreeCAD.ActiveDocument.openTransaction("Create FemBeamSection")
FreeCADGui.addModule("FemBeamSection")
FreeCADGui.doCommand("FemBeamSection.makeFemBeamSection()")
FreeCADGui.doCommand("App.activeDocument()." + FemGui.getActiveAnalysis().Name + ".Member = App.activeDocument()." + FemGui.getActiveAnalysis().Name + ".Member + [App.ActiveDocument.ActiveObject]")
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [FemBeamSection.makeFemBeamSection()]")
def IsActive(self):
if FemGui.getActiveAnalysis():

View File

@ -51,11 +51,11 @@ class FemCommands(object):
elif self.is_active == 'with_document':
active = FreeCADGui.ActiveDocument is not None
elif self.is_active == 'with_analysis':
active = FreeCADGui.ActiveDocument is not None and FemGui.getActiveAnalysis() is not None
active = FemGui.getActiveAnalysis() is not None and self.active_analysis_in_active_doc()
elif self.is_active == 'with_results':
active = FreeCADGui.ActiveDocument is not None and FemGui.getActiveAnalysis() is not None and self.results_present()
active = FemGui.getActiveAnalysis() is not None and self.active_analysis_in_active_doc() and self.results_present()
elif self.is_active == 'with_part_feature':
active = FreeCADGui.ActiveDocument is not None and FemGui.getActiveAnalysis() is not None and self.part_feature_selected()
active = FemGui.getActiveAnalysis() is not None and self.active_analysis_in_active_doc() and self.part_feature_selected()
return active
def results_present(self):
@ -72,3 +72,6 @@ class FemCommands(object):
return True
else:
return False
def active_analysis_in_active_doc(self):
return FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument

View File

@ -37,7 +37,7 @@ __url__ = "http://www.freecadweb.org"
def makeFemShellThickness(thickness=20.0, name="ShellThickness"):
'''makeFemShellThickness([thickness], [name]): creates an shellthickness object to define a plate thickness'''
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython", name)
obj = FemGui.getActiveAnalysis().Document.addObject("Fem::FeaturePython", name)
_FemShellThickness(obj)
obj.Thickness = thickness
if FreeCAD.GuiUp:
@ -56,8 +56,7 @@ class _CommandFemShellThickness:
def Activated(self):
FreeCAD.ActiveDocument.openTransaction("Create FemShellThickness")
FreeCADGui.addModule("FemShellThickness")
FreeCADGui.doCommand("FemShellThickness.makeFemShellThickness()")
FreeCADGui.doCommand("App.activeDocument()." + FemGui.getActiveAnalysis().Name + ".Member = App.activeDocument()." + FemGui.getActiveAnalysis().Name + ".Member + [App.ActiveDocument.ActiveObject]")
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [FemShellThickness.makeFemShellThickness()]")
def IsActive(self):
if FemGui.getActiveAnalysis():

View File

@ -29,13 +29,21 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
finished = QtCore.Signal(int)
def __init__(self, analysis=None):
known_analysis_types = ["static", "frequency"]
## The constructor
# @param analysis - analysis object to be used as the core object.
# @param test_mode - True indicates that no real calculations will take place, so ccx bianry is not required. Used by test module.
# "__init__" tries to use current active analysis in analysis is left empty.
# Rises exception if analysis is not set and there is no active analysis
def __init__(self, analysis=None, test_mode=False):
QtCore.QRunnable.__init__(self)
QtCore.QObject.__init__(self)
self.known_analysis_types = ["static", "frequency"]
if analysis:
## @var analysis
# FEM analysis - the core object. Has to be present.
# It's set to analysis passed in "__init__" or set to current active analysis by default if nothing has been passed to "__init__".
self.analysis = analysis
else:
import FemGui
@ -44,10 +52,18 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
self.update_objects()
self.set_analysis_type()
self.set_eigenmode_parameters()
## @var base_name
# base name of .inp/.frd file (without extension). It is used to construct .inp file path that is passed to CalculiX ccx
self.base_name = ""
## @var results_present
# boolean variable indicating if there are calculation results ready for use
self.results_present = False
self.setup_working_dir()
self.setup_ccx()
if test_mode:
self.ccx_binary_present = True
else:
self.ccx_binary_present = False
self.setup_ccx()
else:
raise Exception('FEM: No active analysis found!')
@ -56,7 +72,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
def purge_results(self):
for m in self.analysis.Member:
if (m.isDerivedFrom('Fem::FemResultObject')):
FreeCAD.ActiveDocument.removeObject(m.Name)
self.analysis.Document.removeObject(m.Name)
self.results_present = False
## Resets mesh deformation
@ -80,6 +96,13 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
self.reset_mesh_color()
self.reset_mesh_deformation()
## Sets mesh color using selected type of results (Sabs by default)
# @param self The python object self
# @param result_type Type of FEM result, allowed are:
# - U1, U2, U3 - deformation
# - Uabs - absolute deformation
# - Sabs - Von Mises stress
# @param limit cutoff value. All values over the limit are treated as equel to the limit. Useful for filtering out hot spots.
def show_result(self, result_type="Sabs", limit=None):
self.update_objects()
if result_type == "None":
@ -96,6 +119,10 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
values = list(d[match[result_type]])
self.show_color_by_scalar_with_cutoff(values, limit)
## Sets mesh color using list of values. Internally used by show_result function.
# @param self The python object self
# @param values list of values
# @param limit cutoff value. All values over the limit are treated as equel to the limit. Useful for filtering out hot spots.
def show_color_by_scalar_with_cutoff(self, values, limit=None):
if limit:
filtered_values = []
@ -120,10 +147,22 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
# [{'Object':pressure_constraints, 'xxxxxxxx':value}, {}, ...]
# [{'Object':beam_sections, 'xxxxxxxx':value}, {}, ...]
# [{'Object':shell_thicknesses, 'xxxxxxxx':value}, {}, ...]
## @var mesh
# mesh of the analysis. Used to generate .inp file and to show results
self.mesh = None
self.material = []
## @var fixed_constraints
# set of fixed constraints from the analysis. Updated with update_objects
# Individual constraints are "Fem::ConstraintFixed" type
self.fixed_constraints = []
## @var force_constraints
# set of force constraints from the analysis. Updated with update_objects
# Individual constraints are "Fem::ConstraintForce" type
self.force_constraints = []
## @var pressure_constraints
# set of pressure constraints from the analysis. Updated with update_objects
# Individual constraints are "Fem::ConstraintPressure" type
self.pressure_constraints = []
self.beam_sections = []
self.shell_thicknesses = []
@ -162,6 +201,11 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
message += "No active Analysis\n"
if self.analysis_type not in self.known_analysis_types:
message += "Unknown analysis type: {}\n".format(self.analysis_type)
if not self.working_dir:
message += "Working directory not set\n"
import os
if not (os.path.isdir(self.working_dir)):
message += "Working directory \'{}\' doesn't exist.".format(self.working_dir)
if not self.mesh:
message += "No mesh object in the Analysis\n"
if not self.material:
@ -207,7 +251,9 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
import multiprocessing
import os
import subprocess
if self.inp_file_name != "":
self.ccx_stdout = ""
self.ccx_stderr = ""
if self.inp_file_name != "" and self.ccx_binary_present:
ont_backup = os.environ.get('OMP_NUM_THREADS')
if not ont_backup:
ont_backup = ""
@ -226,7 +272,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
return p.returncode
return -1
## sets eigenmode parameters for CalculiX frequency analysis
## Sets eigenmode parameters for CalculiX frequency analysis
# @param self The python object self
# @param number number of eigenmodes that wll be calculated, default 10
# @param limit_low lower value of requested eigenfrequency range, default 0.0
@ -234,6 +280,9 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
def set_eigenmode_parameters(self, number=10, limit_low=0.0, limit_high=1000000.0):
self.eigenmode_parameters = (number, limit_low, limit_high)
## Sets base_name
# @param self The python object self
# @param base_name base name of .inp/.frd file (without extension). It is used to construct .inp file path that is passed to CalculiX ccx
def set_base_name(self, base_name=None):
if base_name is None:
self.base_name = ""
@ -242,34 +291,55 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
# Update inp file name
self.set_inp_file_name()
## sets inp file name that is used to determine location and name of frd result file.
## Sets inp file name that is used to determine location and name of frd result file.
# Normally inp file name is set set by write_inp_file
# Can be used to read mock calculations file
# @param self The python object self
# @inp_file_name .inp file name. If empty the .inp file path is constructed from working_dir, base_name and string ".inp"
def set_inp_file_name(self, inp_file_name=None):
if inp_file_name is not None:
self.inp_file_name = inp_file_name
else:
self.inp_file_name = self.working_dir + '/' + self.base_name + '.inp'
def set_analysis_type(self, analysis_type=None):
if analysis_type is None:
self.analysis_type = "static"
else:
self.analysis_type = analysis_type
## Sets working dir for ccx execution. Called with no working_dir uses WorkingDir for FEM preferences
## Sets analysis type.
# @param self The python object self
# @working_dir directory to be used for .inp file and ccx execution
def setup_working_dir(self, working_dir=None):
if working_dir is None:
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
self.working_dir = self.fem_prefs.GetString("WorkingDir", "/tmp")
# @param analysis_type type of the analysis. Allowed values are:
# - static
# - frequency
def set_analysis_type(self, analysis_type=None):
if analysis_type is not None:
self.analysis_type = analysis_type
else:
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
self.analysis_type = self.fem_prefs.GetString("AnalysisType", "static")
## Sets working dir for ccx execution. Called with no working_dir uses WorkingDir from FEM preferences
# @param self The python object self
# @working_dir directory to be used for writing .inp file and executing CalculiX ccx
def setup_working_dir(self, working_dir=None):
import os
if working_dir is not None:
self.working_dir = working_dir
else:
self.working_dir = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem").GetString("WorkingDir")
if not (os.path.isdir(self.working_dir)):
try:
os.makedirs(self.working_dir)
except:
print ("Dir \'{}\' doesn't exist and cannot be created.".format(self.working_dir))
import tempfile
self.working_dir = tempfile.gettempdir()
print ("Dir \'{}\' will be used instead.".format(self.working_dir))
# Update inp file name
self.set_inp_file_name()
def setup_ccx(self, ccx_binary=None):
## Sets CalculiX ccx binary path and velidates if the binary can be executed
# @param self The python object self
# @ccx_binary path to ccx binary, default is guessed: "bin/ccx" windows, "ccx" for other systems
# @ccx_binary_sig expected output form ccx when run empty. Default value is "CalculiX.exe -i jobname"
def setup_ccx(self, ccx_binary=None, ccx_binary_sig="CalculiX"):
if not ccx_binary:
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
ccx_binary = self.fem_prefs.GetString("ccxBinaryPath", "")
@ -282,8 +352,23 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
else:
ccx_binary = "ccx"
self.ccx_binary = ccx_binary
import subprocess
try:
p = subprocess.Popen([self.ccx_binary], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=False)
ccx_stdout, ccx_stderr = p.communicate()
if ccx_binary_sig in ccx_stdout:
self.ccx_binary_present = True
except OSError, e:
FreeCAD.Console.PrintError(e.message)
if e.errno == 2:
raise Exception("FEM: CalculiX binary ccx \'{}\' not found. Please set it in FEM preferences.".format(ccx_binary))
except Exception as e:
FreeCAD.Console.PrintError(e.message)
raise Exception("FEM: CalculiX ccx \'{}\' output \'{}\' doesn't contain expected phrase \'{}\'. Please use ccx 2.6 or newer".
format(ccx_binary, ccx_stdout, ccx_binary_sig))
## Load results of ccx calculiations from .frd file.
## Load results of ccx calculations from .frd file.
# @param self The python object self
def load_results(self):
import ccxFrdReader
@ -306,7 +391,7 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
self.result_object = m
break
if not self.result_object:
raise ("{} doesn't exist".format(results_name))
raise Exception("{} doesn't exist".format(results_name))
def run(self):
ret_code = 0
@ -330,9 +415,13 @@ class FemTools(QtCore.QRunnable, QtCore.QObject):
print self.ccx_stdout
print "--------end of stdout---------"
## returns minimum, average and maximum value for provided result type
## Returns minimum, average and maximum value for provided result type
# @param self The python object self
# @result_type Type of FEM result, allowed U1, U2, U3, Uabs, Sabs and None
# @param result_type Type of FEM result, allowed are:
# - U1, U2, U3 - deformation
# - Uabs - absolute deformation
# - Sabs - Von Mises stress
# - None - always return (0.0, 0.0, 0.0)
def get_stats(self, result_type):
stats = (0.0, 0.0, 0.0)
for m in self.analysis.Member:

View File

@ -105,7 +105,6 @@ void FemGuiExport initFemGui()
Base::Interpreter().loadModule("FemCommands");
Base::Interpreter().loadModule("_CommandMechanicalShowResult");
Base::Interpreter().loadModule("_CommandFrequencyAnalysis");
Base::Interpreter().loadModule("_CommandQuickAnalysis");
Base::Interpreter().loadModule("_CommandPurgeFemResults");
Base::Interpreter().loadModule("_CommandMechanicalJobControl");

View File

@ -240,7 +240,7 @@ void CmdFemConstraintBearing::activated(int iMsg)
bool CmdFemConstraintBearing::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//=====================================================================================
@ -278,7 +278,7 @@ void CmdFemConstraintFixed::activated(int iMsg)
bool CmdFemConstraintFixed::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//=====================================================================================
@ -317,7 +317,7 @@ void CmdFemConstraintForce::activated(int iMsg)
bool CmdFemConstraintForce::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//=====================================================================================
@ -357,7 +357,7 @@ void CmdFemConstraintPressure::activated(int iMsg)
bool CmdFemConstraintPressure::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//=====================================================================================
@ -395,7 +395,7 @@ void CmdFemConstraintGear::activated(int iMsg)
bool CmdFemConstraintGear::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
//=====================================================================================
@ -438,7 +438,7 @@ void CmdFemConstraintPulley::activated(int iMsg)
bool CmdFemConstraintPulley::isActive(void)
{
return hasActiveDocument();
return FemGui::ActiveAnalysisObserver::instance()->hasActiveObject();
}
// #####################################################################################################

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>555</width>
<height>429</height>
<height>453</height>
</rect>
</property>
<property name="windowTitle">
@ -193,6 +193,73 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_analysis_params">
<property name="title">
<string>Default analysis type</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="Gui::PrefComboBox" name="cb_analysis_type">
<property name="minimumSize">
<size>
<width>148</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Default type on analysis</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>AnalysisType</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem</cstring>
</property>
<item>
<property name="text">
<string>Static</string>
</property>
<property name="icon">
<iconset resource="Resources/Fem.qrc">
<normaloff>:/icons/fem-new-analysis.svg</normaloff>:/icons/fem-new-analysis.svg</iconset>
</property>
</item>
<item>
<property name="text">
<string>Frequency</string>
</property>
<property name="icon">
<iconset resource="Resources/Fem.qrc">
<normaloff>:/icons/fem-frequency-analysis.svg</normaloff>:/icons/fem-frequency-analysis.svg</iconset>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_materials">
<property name="title">
@ -336,6 +403,11 @@
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefComboBox</class>
<extends>QComboBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources/Fem.qrc"/>

View File

@ -25,6 +25,7 @@
#include "PreCompiled.h"
#include "Gui/Application.h"
#include "DlgSettingsFemImp.h"
#include <Gui/PrefWidgets.h>
@ -43,10 +44,15 @@ DlgSettingsFemImp::~DlgSettingsFemImp()
void DlgSettingsFemImp::saveSettings()
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Fem");
hGrp->SetInt("AnalysisType", cb_analysis_type->currentIndex());
fc_ccx_working_directory->onSave();
cb_int_editor->onSave();
fc_ext_editor->onSave();
fc_ccx_binary->onSave();
cb_analysis_type->onSave();
cb_use_built_in_materials->onSave();
cb_use_mat_from_config_dir->onSave();
cb_use_mat_from_custom_dir->onSave();
@ -59,10 +65,16 @@ void DlgSettingsFemImp::loadSettings()
cb_int_editor->onRestore();
fc_ext_editor->onRestore();
fc_ccx_binary->onRestore();
cb_analysis_type->onRestore();
cb_use_built_in_materials->onRestore();
cb_use_mat_from_config_dir->onRestore();
cb_use_mat_from_custom_dir->onRestore();
fc_custom_mat_dir->onRestore();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Fem");
int index = hGrp->GetInt("AnalysisType", 0);
if (index > -1) cb_analysis_type->setCurrentIndex(index);
}
/**
@ -71,7 +83,9 @@ void DlgSettingsFemImp::loadSettings()
void DlgSettingsFemImp::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
int c_index = cb_analysis_type->currentIndex();
retranslateUi(this);
cb_analysis_type->setCurrentIndex(c_index);
}
else {
QWidget::changeEvent(e);

View File

@ -62,6 +62,9 @@
#include <queue>
#include <bitset>
// boost
#include <boost/bind.hpp>
#ifdef FC_OS_WIN32
# include <windows.h>
#endif

View File

@ -274,7 +274,7 @@ TaskDlgFemConstraintGear::TaskDlgFemConstraintGear(ViewProviderFemConstraintGear
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintGear(ConstraintView, 0, "Fem_ConstraintGear");
this->parameter = new TaskFemConstraintGear(ConstraintView, 0, "fem-constraint-gear");
Content.push_back(parameter);
}

View File

@ -50,7 +50,7 @@ using namespace Gui;
/* TRANSLATOR FemGui::TaskFemConstraintPulley */
TaskFemConstraintPulley::TaskFemConstraintPulley(ViewProviderFemConstraintPulley *ConstraintView,QWidget *parent)
: TaskFemConstraintGear(ConstraintView, parent, "Fem_ConstraintPulley")
: TaskFemConstraintGear(ConstraintView, parent, "fem-constraint-pulley")
{
connect(ui->spinOtherDiameter, SIGNAL(valueChanged(double)),
this, SLOT(onOtherDiameterChanged(double)));

View File

@ -25,12 +25,16 @@
#ifndef _PreComp_
# include <Standard_math.hxx>
# include <boost/bind.hpp>
# include <QAction>
# include <QMenu>
#endif
#include "ViewProviderAnalysis.h"
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/Control.h>
#include <Gui/ActionFunction.h>
#include <Mod/Fem/App/FemAnalysis.h>
#include <Mod/Fem/App/FemMeshObject.h>
@ -43,10 +47,7 @@
using namespace FemGui;
/* TRANSLATOR FemGui::ViewProviderFemAnalysis */
PROPERTY_SOURCE(FemGui::ViewProviderFemAnalysis, Gui::ViewProviderDocumentObject)
@ -85,10 +86,9 @@ std::vector<App::DocumentObject*> ViewProviderFemAnalysis::claimChildren(void)co
void ViewProviderFemAnalysis::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
//QAction* act;
//act = menu->addAction(QObject::tr("Edit pad"), receiver, member);
//act->setData(QVariant((int)ViewProvider::Default));
//PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member);
Gui::ActionFunction* func = new Gui::ActionFunction(menu);
QAction* act = menu->addAction(tr("Activate analysis"));
func->trigger(act, boost::bind(&ViewProviderFemAnalysis::doubleClicked, this));
}
bool ViewProviderFemAnalysis::setEdit(int ModNum)
@ -119,11 +119,10 @@ bool ViewProviderFemAnalysis::setEdit(int ModNum)
// Gui::Control().showDialog(padDlg);
// else
Fem::FemAnalysis* pcAna = static_cast<Fem::FemAnalysis*>(this->getObject());
Gui::Control().showDialog(new TaskDlgAnalysis(pcAna));
return true;
//Fem::FemAnalysis* pcAna = static_cast<Fem::FemAnalysis*>(this->getObject());
//Gui::Control().showDialog(new TaskDlgAnalysis(pcAna));
//return true;
return false;
}
else {
return Gui::ViewProviderDocumentObject::setEdit(ModNum);
@ -176,6 +175,8 @@ bool ViewProviderFemAnalysis::canDragObject(App::DocumentObject* obj) const
return true;
else if (obj->getTypeId().isDerivedFrom(Fem::FemSetObject::getClassTypeId()))
return true;
else if (obj->getTypeId().isDerivedFrom(Base::Type::fromName("Fem::FeaturePython")))
return true;
else if (obj->getTypeId().isDerivedFrom(App::MaterialObject::getClassTypeId()))
return true;
else

View File

@ -27,6 +27,7 @@
#include <Gui/ViewProviderGeometryObject.h>
#include <Gui/ViewProviderBuilder.h>
#include <Gui/ViewProviderPythonFeature.h>
#include <QCoreApplication>
class SoCoordinate3;
class SoDrawStyle;
@ -42,6 +43,7 @@ namespace FemGui
class FemGuiExport ViewProviderFemAnalysis : public Gui::ViewProviderDocumentObject
{
Q_DECLARE_TR_FUNCTIONS(FemGui::ViewProviderFemAnalysis)
PROPERTY_HEADER(FemGui::ViewProviderAnalysis);
public:

View File

@ -72,7 +72,6 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "Separator"
<< "Fem_MechanicalJobControl"
<< "Fem_Quick_Analysis"
<< "Fem_Frequency_Analysis"
<< "Fem_PurgeResults"
<< "Fem_ShowResult";
return root;
@ -102,7 +101,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Separator"
<< "Fem_MechanicalJobControl"
<< "Fem_Quick_Analysis"
<< "Fem_Frequency_Analysis"
<< "Fem_PurgeResults"
<< "Fem_ShowResult";

View File

@ -52,9 +52,29 @@ class FemWorkbench (Workbench):
ccx_path = p1.stdout.read().split('\n')[0]
elif system() == 'Windows':
ccx_path = FreeCAD.getHomePath() + 'bin/ccx.exe'
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem").SetString("ccxBinaryPath", ccx_path)
if ccx_path:
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem").SetString("ccxBinaryPath", ccx_path)
else:
FreeCAD.Console.PrintError("CalculiX ccx binary not found! Please set it manually in FEM preferences.\n")
except Exception as e:
FreeCAD.Console.PrintError(e.message)
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
import os
working_dir = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem").GetString("WorkingDir")
if not (os.path.isdir(working_dir)):
try:
os.makedirs(working_dir)
except:
print ("Dir \'{}\' from FEM preferences doesn't exist and cannot be created.".format(working_dir))
import tempfile
working_dir = tempfile.gettempdir()
print ("Dir \'{}\' will be used instead.".format(working_dir))
if working_dir:
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem").SetString("WorkingDir", working_dir)
else:
FreeCAD.Console.PrintError("Setting working directory \'{}\' for ccx failed!\n")
def GetClassName(self):
return "FemGui::Workbench"

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>193</width>
<height>384</height>
<width>258</width>
<height>458</height>
</rect>
</property>
<property name="windowTitle">
@ -15,56 +15,103 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="le_working_dir">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
<widget class="QGroupBox" name="gb_working_dir">
<property name="title">
<string>Working directory</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="le_working_dir">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="tb_choose_working_dir">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_analysis_type">
<property name="title">
<string>Analysis type</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="Gui::PrefRadioButton" name="rb_static_analysis">
<property name="text">
<string>Static</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefRadioButton" name="rb_frequency_analysis">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gl_actions">
<item row="0" column="0">
<widget class="QPushButton" name="pb_write_inp">
<property name="text">
<string>Write .inp file</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="tb_choose_working_dir">
<item row="0" column="1">
<widget class="QPushButton" name="pb_edit_inp">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="text">
<string>...</string>
<string>Edit .inp file</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="pb_run_ccx">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Run Calculix</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_write">
<property name="text">
<string>Write Calculix Input File</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_edit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Edit Calculix Input File</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_generate">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Run Calculix</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit_Output">
<property name="lineWrapMode">
@ -73,7 +120,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_Time">
<widget class="QLabel" name="l_time">
<property name="font">
<font>
<pointsize>12</pointsize>
@ -86,6 +133,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::PrefRadioButton</class>
<extends>QRadioButton</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -21,6 +21,7 @@
# ***************************************************************************
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
@ -45,13 +46,15 @@ def makeMechanicalMaterial(name):
return obj
class _CommandMechanicalMaterial:
class _CommandMechanicalMaterial(FemCommands):
"the Fem Material command definition"
def GetResources(self):
return {'Pixmap': 'fem-material',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_Material", "Mechanical material..."),
'Accel': "M, M",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_Material", "Creates or edit the mechanical material definition.")}
def __init__(self):
super(_CommandMechanicalMaterial, self).__init__()
self.resources = {'Pixmap': 'fem-material',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_Material", "Mechanical material..."),
'Accel': "M, M",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_Material", "Creates or edit the mechanical material definition.")}
self.is_active = 'with_analysis'
def Activated(self):
MatObj = None
@ -60,6 +63,9 @@ class _CommandMechanicalMaterial:
MatObj = i
if (not MatObj):
femDoc = FemGui.getActiveAnalysis().Document
if FreeCAD.ActiveDocument is not femDoc:
FreeCADGui.setActiveDocument(femDoc)
FreeCAD.ActiveDocument.openTransaction("Create Material")
FreeCADGui.addModule("MechanicalMaterial")
FreeCADGui.doCommand("MechanicalMaterial.makeMechanicalMaterial('MechanicalMaterial')")
@ -67,14 +73,10 @@ class _CommandMechanicalMaterial:
FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name,0)")
# FreeCADGui.doCommand("Fem.makeMaterial()")
else:
if FreeCAD.ActiveDocument is not MatObj.Document:
FreeCADGui.setActiveDocument(MatObj.Document)
FreeCADGui.doCommand("Gui.activeDocument().setEdit('" + MatObj.Name + "',0)")
def IsActive(self):
if FemGui.getActiveAnalysis():
return True
else:
return False
class _MechanicalMaterial:
"The Material object"
@ -153,11 +155,13 @@ class _MechanicalMaterialTaskPanel:
def accept(self):
self.obj.Material = self.material
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
doc.Document.recompute()
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
def goMatWeb(self):
import webbrowser

View File

@ -117,9 +117,11 @@ class FemTest(unittest.TestCase):
def compare_inp_files(self, file_name1, file_name2):
file1 = open(file_name1, 'r')
file2 = open(file_name2, 'r')
f1 = file1.readlines()
file1.close()
file2 = open(file_name2, 'r')
f2 = file2.readlines()
file2.close()
lf1 = [l for l in f1 if not l.startswith('** written ')]
lf2 = [l for l in f2 if not l.startswith('** written ')]
import difflib
@ -127,8 +129,8 @@ class FemTest(unittest.TestCase):
result = ''
for l in diff:
result += l
file1.close()
file2.close()
if result:
result = "Comparing {} to {} failed!\n".format(file_name1, file_name2) + result
return result
def compare_stats(self, fea, stat_file=None):
@ -179,17 +181,21 @@ class FemTest(unittest.TestCase):
self.assertTrue(self.pressure_constraint, "FemTest of new pressure constraint failed")
self.analysis.Member = self.analysis.Member + [self.pressure_constraint]
fea = FemTools.FemTools(self.analysis)
fcc_print('Checking FEM inp file prerequisites...')
fea = FemTools.FemTools(self.analysis, test_mode=True)
fcc_print('Setting up working directory {}'.format(static_analysis_dir))
fea.setup_working_dir(static_analysis_dir)
self.assertTrue(True if fea.working_dir == static_analysis_dir else False,
"Setting working directory {} failed".format(static_analysis_dir))
fcc_print('Checking FEM inp file prerequisites for static analysis...')
error = fea.check_prerequisites()
self.assertFalse(error, "FemTools check_prerequisites returned error message: {}".format(error))
fcc_print('Checking FEM inp file write...')
fcc_print('Setting up working directory {}'.format(static_analysis_dir))
fea.setup_working_dir(static_analysis_dir)
self.assertTrue(True if fea.working_dir == static_analysis_dir else False,
"Setting working directory {} failed".format(static_analysis_dir))
fcc_print('Setting analysis type to \'static\"')
fea.set_analysis_type("static")
self.assertTrue(True if fea.analysis_type == 'static' else False, "Setting anlysis type to \'static\' failed")
fcc_print('Writing {}/{}.inp for static analysis'.format(static_analysis_dir, mesh_name))
error = fea.write_inp_file()
@ -232,6 +238,10 @@ class FemTest(unittest.TestCase):
self.assertTrue(True if fea.working_dir == frequency_analysis_dir else False,
"Setting working directory {} failed".format(frequency_analysis_dir))
fcc_print('Checking FEM inp file prerequisites for frequency analysis...')
error = fea.check_prerequisites()
self.assertFalse(error, "FemTools check_prerequisites returned error message: {}".format(error))
fcc_print('Writing {}/{}.inp for frequency analysis'.format(frequency_analysis_dir, mesh_name))
error = fea.write_inp_file()
self.assertFalse(error, "Writing failed")

View File

@ -1,64 +0,0 @@
#***************************************************************************
#* *
#* Copyright (c) 2013-2015 - Juergen Riegel <FreeCAD@juergen-riegel.net> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
__title__ = "Command Frequency Analysis"
__author__ = "Juergen Riegel"
__url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
from FemTools import FemTools
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
class _CommandFrequencyAnalysis(FemCommands):
def __init__(self):
super(_CommandFrequencyAnalysis, self).__init__()
self.resources = {'Pixmap': 'fem-frequency-analysis',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_Frequency_Analysis", "Run frequency analysis with CalculiX ccx"),
'Accel': "R, F",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_Frequency_Analysis", "Write .inp file and run frequency analysis with CalculiX ccx")}
self.is_active = 'with_analysis'
def Activated(self):
def load_results(ret_code):
if ret_code == 0:
self.fea.load_results()
else:
print "CalculiX failed ccx finished with error {}".format(ret_code)
self.fea = FemTools()
self.fea.reset_all()
self.fea.set_analysis_type('frequency')
message = self.fea.check_prerequisites()
if message:
QtGui.QMessageBox.critical(None, "Missing prerequisite", message)
return
self.fea.finished.connect(load_results)
QtCore.QThreadPool.globalInstance().start(self.fea)
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Fem_Frequency_Analysis', _CommandFrequencyAnalysis())

View File

@ -46,7 +46,6 @@ class _CommandNewMechanicalAnalysis(FemCommands):
FreeCAD.ActiveDocument.openTransaction("Create Analysis")
FreeCADGui.addModule("FemGui")
FreeCADGui.addModule("MechanicalAnalysis")
#FreeCADGui.doCommand("FreeCADGui.ActiveDocument.ActiveView.setAxisCross(True)")
FreeCADGui.doCommand("MechanicalAnalysis.makeMechanicalAnalysis('MechanicalAnalysis')")
FreeCADGui.doCommand("FemGui.setActiveAnalysis(App.activeDocument().ActiveObject)")
sel = FreeCADGui.Selection.getSelection()
@ -57,12 +56,7 @@ class _CommandNewMechanicalAnalysis(FemCommands):
FreeCADGui.doCommand("App.activeDocument().addObject('Fem::FemMeshShapeNetgenObject', '" + sel[0].Name + "_Mesh')")
FreeCADGui.doCommand("App.activeDocument().ActiveObject.Shape = App.activeDocument()." + sel[0].Name)
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.activeDocument().ActiveObject]")
#FreeCADGui.doCommand("Gui.activeDocument().hide('" + sel[0].Name + "')")
#FreeCADGui.doCommand("App.activeDocument().ActiveObject.touch()")
#FreeCADGui.doCommand("App.activeDocument().recompute()")
FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name)")
#FreeCAD.ActiveDocument.commitTransaction()
FreeCADGui.Selection.clearSelection()
if FreeCAD.GuiUp:

View File

@ -48,7 +48,7 @@ class _CommandQuickAnalysis(FemCommands):
self.fea.load_results()
self.show_results_on_mesh()
else:
print "CalculiX failed ccx finished with error {}".format(ret_code)
print ("CalculiX failed ccx finished with error {}".format(ret_code))
self.fea = FemTools()
self.fea.reset_all()

View File

@ -24,13 +24,20 @@ __title__ = "Fem Analysis"
__author__ = "Juergen Riegel"
__url__ = "http://www.freecadweb.org"
import FreeCAD
from FemTools import FemTools
class _FemAnalysis:
"The FemAnalysis container object"
def __init__(self, obj):
self.Type = "FemAnalysis"
obj.Proxy = self
obj.addProperty("App::PropertyString", "OutputDir", "Base", "Directory where the jobs get generated")
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
obj.addProperty("App::PropertyEnumeration", "AnalysisType", "Fem", "Type of the analysis")
obj.AnalysisType = FemTools.known_analysis_types
analysis_type = fem_prefs.GetInt("AnalysisType", 0)
obj.AnalysisType = FemTools.known_analysis_types[analysis_type]
def execute(self, obj):
return

View File

@ -45,7 +45,7 @@ class _JobControlTaskPanel:
ccx_binary = self.fem_prefs.GetString("ccxBinaryPath", "")
if ccx_binary:
self.CalculixBinary = ccx_binary
print "Using ccx binary path from FEM preferences: {}".format(ccx_binary)
print ("Using ccx binary path from FEM preferences: {}".format(ccx_binary))
else:
from platform import system
if system() == 'Linux':
@ -58,6 +58,7 @@ class _JobControlTaskPanel:
self.working_dir = self.fem_prefs.GetString("WorkingDir", '/tmp')
self.analysis_object = analysis_object
self.Calculix = QtCore.QProcess()
self.Timer = QtCore.QTimer()
self.Timer.start(300)
@ -66,9 +67,11 @@ class _JobControlTaskPanel:
#Connect Signals and Slots
QtCore.QObject.connect(self.form.tb_choose_working_dir, QtCore.SIGNAL("clicked()"), self.choose_working_dir)
QtCore.QObject.connect(self.form.pushButton_write, QtCore.SIGNAL("clicked()"), self.write_input_file_handler)
QtCore.QObject.connect(self.form.pushButton_edit, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile)
QtCore.QObject.connect(self.form.pushButton_generate, QtCore.SIGNAL("clicked()"), self.runCalculix)
QtCore.QObject.connect(self.form.pb_write_inp, QtCore.SIGNAL("clicked()"), self.write_input_file_handler)
QtCore.QObject.connect(self.form.pb_edit_inp, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile)
QtCore.QObject.connect(self.form.pb_run_ccx, QtCore.SIGNAL("clicked()"), self.runCalculix)
QtCore.QObject.connect(self.form.rb_static_analysis, QtCore.SIGNAL("clicked()"), self.select_static_analysis)
QtCore.QObject.connect(self.form.rb_frequency_analysis, QtCore.SIGNAL("clicked()"), self.select_frequency_analysis)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("started()"), self.calculixStarted)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("stateChanged(QProcess::ProcessState)"), self.calculixStateChanged)
@ -106,16 +109,16 @@ class _JobControlTaskPanel:
def UpdateText(self):
if(self.Calculix.state() == QtCore.QProcess.ProcessState.Running):
self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def calculixError(self, error):
print "Error()", error
print ("Error() {}".format(error))
self.femConsoleMessage("CalculiX execute error: {}".format(error), "#FF0000")
def calculixStarted(self):
print "calculixStarted()"
print self.Calculix.state()
self.form.pushButton_generate.setText("Break Calculix")
print ("calculixStarted()")
print (self.Calculix.state())
self.form.pb_run_ccx.setText("Break CalculiX")
def calculixStateChanged(self, newState):
if (newState == QtCore.QProcess.ProcessState.Starting):
@ -126,8 +129,8 @@ class _JobControlTaskPanel:
self.femConsoleMessage("CalculiX stopped.")
def calculixFinished(self, exitCode):
print "calculixFinished()", exitCode
print self.Calculix.state()
print ("calculixFinished() {}".format(exitCode))
print (self.Calculix.state())
# Restore previous cwd
QtCore.QDir.setCurrent(self.cwd)
@ -137,10 +140,9 @@ class _JobControlTaskPanel:
self.femConsoleMessage("Calculix done!", "#00AA00")
self.form.pushButton_generate.setText("Re-run Calculix")
print "Loading results...."
self.form.pb_run_ccx.setText("Re-run CalculiX")
self.femConsoleMessage("Loading result sets...")
self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemTools()
fea.reset_all()
frd_result_file = os.path.splitext(self.inp_file_name)[0] + '.frd'
@ -151,7 +153,7 @@ class _JobControlTaskPanel:
self.femConsoleMessage("Loading results done!", "#00AA00")
else:
self.femConsoleMessage("Loading results failed! Results file doesn\'t exist", "#FF0000")
self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
@ -159,6 +161,10 @@ class _JobControlTaskPanel:
def update(self):
'fills the widgets'
self.form.le_working_dir.setText(self.working_dir)
if self.analysis_object.AnalysisType == 'static':
self.form.rb_static_analysis.setChecked(True)
elif self.analysis_object.AnalysisType == 'frequency':
self.form.rb_frequency_analysis.setChecked(True)
return
def accept(self):
@ -168,13 +174,14 @@ class _JobControlTaskPanel:
FreeCADGui.Control.closeDialog()
def choose_working_dir(self):
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
self.working_dir = QtGui.QFileDialog.getExistingDirectory(None,
'Choose CalculiX working directory',
self.fem_prefs.GetString("WorkingDir", '/tmp'))
if self.working_dir:
self.fem_prefs.SetString("WorkingDir", str(self.working_dir))
self.form.le_working_dir.setText(self.working_dir)
current_wd = get_working_dir()
wd = QtGui.QFileDialog.getExistingDirectory(None, 'Choose CalculiX working directory',
current_wd)
if wd:
self.analysis_object.WorkingDir = wd
else:
self.analysis_object.WorkingDir = current_wd
self.form.le_working_dir.setText(self.analysis_object.WorkingDir)
def write_input_file_handler(self):
QApplication.restoreOverrideCursor()
@ -182,13 +189,14 @@ class _JobControlTaskPanel:
QApplication.setOverrideCursor(Qt.WaitCursor)
self.inp_file_name = ""
fea = FemTools()
fea.set_analysis_type(self.analysis_object.AnalysisType)
fea.update_objects()
fea.write_inp_file()
if fea.inp_file_name != "":
self.inp_file_name = fea.inp_file_name
self.femConsoleMessage("Write completed.")
self.form.pushButton_edit.setEnabled(True)
self.form.pushButton_generate.setEnabled(True)
self.form.pb_edit_inp.setEnabled(True)
self.form.pb_run_ccx.setEnabled(True)
else:
self.femConsoleMessage("Write .inp file failed!", "#FF0000")
QApplication.restoreOverrideCursor()
@ -196,7 +204,7 @@ class _JobControlTaskPanel:
def check_prerequisites_helper(self):
self.Start = time.time()
self.femConsoleMessage("Check dependencies...")
self.form.label_Time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemTools()
fea.update_objects()
@ -213,7 +221,7 @@ class _JobControlTaskPanel:
self.ext_editor_process.start(ext_editor_path, [filename])
def editCalculixInputFile(self):
print 'editCalculixInputFile {}'.format(self.inp_file_name)
print ('editCalculixInputFile {}'.format(self.inp_file_name))
if self.fem_prefs.GetBool("UseInternalEditor", True):
FemGui.open(self.inp_file_name)
else:
@ -221,18 +229,18 @@ class _JobControlTaskPanel:
if ext_editor_path:
self.start_ext_editor(ext_editor_path, self.inp_file_name)
else:
print "External editor is not defined in FEM preferences. Falling back to internal editor"
print ("External editor is not defined in FEM preferences. Falling back to internal editor")
FemGui.open(self.inp_file_name)
def runCalculix(self):
print 'runCalculix'
print ('runCalculix')
self.Start = time.time()
self.femConsoleMessage("CalculiX binary: {}".format(self.CalculixBinary))
self.femConsoleMessage("Run Calculix...")
# run Calculix
print 'run Calculix at: ', self.CalculixBinary, ' with: ', os.path.splitext(self.inp_file_name)[0]
print ('run Calculix at: {} with: {}'.format(self.CalculixBinary, os.path.splitext(self.inp_file_name)[0]))
# change cwd because ccx may crash if directory has no write permission
# there is also a limit of the length of file names so jump to the document directory
self.cwd = QtCore.QDir.currentPath()
@ -241,3 +249,30 @@ class _JobControlTaskPanel:
self.Calculix.start(self.CalculixBinary, ['-i', fi.baseName()])
QApplication.restoreOverrideCursor()
def select_analysis_type(self, analysis_type):
if self.analysis_object.AnalysisType != analysis_type:
self.analysis_object.AnalysisType = analysis_type
self.form.pb_edit_inp.setEnabled(False)
self.form.pb_run_ccx.setEnabled(False)
def select_static_analysis(self):
self.select_analysis_type('static')
def select_frequency_analysis(self):
self.select_analysis_type('frequency')
#Code duplication!!!!
def get_working_dir():
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
working_dir = fem_prefs.GetString("WorkingDir", "")
if not (os.path.isdir(working_dir)):
try:
os.path.makedirs(working_dir)
except:
print ("Dir \'{}\' from FEM preferences doesn't exist and cannot be created.".format(working_dir))
import tempfile
working_dir = tempfile.gettempdir()
print ("Dir \'{}\' will be used instead.".format(working_dir))
return working_dir

View File

@ -290,51 +290,58 @@ void PropertyPartShape::SaveDocFile (Base::Writer &writer) const
shape.exportBinary(writer.Stream());
}
else {
// create a temporary file and copy the content to the zip stream
// once the tmp. filename is known use always the same because otherwise
// we may run into some problems on the Linux platform
static Base::FileInfo fi(App::Application::getTempFileName());
bool direct = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", false);
if (!direct) {
// create a temporary file and copy the content to the zip stream
// once the tmp. filename is known use always the same because otherwise
// we may run into some problems on the Linux platform
static Base::FileInfo fi(App::Application::getTempFileName());
if (!BRepTools::Write(myShape,(const Standard_CString)fi.filePath().c_str())) {
// Note: Do NOT throw an exception here because if the tmp. file could
// not be created we should not abort.
// We only print an error message but continue writing the next files to the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("Shape of '%s' cannot be written to BRep file '%s'\n",
obj->Label.getValue(),fi.filePath().c_str());
}
else {
Base::Console().Error("Cannot save BRep file '%s'\n", fi.filePath().c_str());
if (!BRepTools::Write(myShape,(const Standard_CString)fi.filePath().c_str())) {
// Note: Do NOT throw an exception here because if the tmp. file could
// not be created we should not abort.
// We only print an error message but continue writing the next files to the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("Shape of '%s' cannot be written to BRep file '%s'\n",
obj->Label.getValue(),fi.filePath().c_str());
}
else {
Base::Console().Error("Cannot save BRep file '%s'\n", fi.filePath().c_str());
}
std::stringstream ss;
ss << "Cannot save BRep file '" << fi.filePath() << "'";
writer.addError(ss.str());
}
std::stringstream ss;
ss << "Cannot save BRep file '" << fi.filePath() << "'";
writer.addError(ss.str());
Base::ifstream file(fi, std::ios::in | std::ios::binary);
if (file){
unsigned long ulSize = 0;
std::streambuf* buf = file.rdbuf();
if (buf) {
unsigned long ulCurr;
ulCurr = buf->pubseekoff(0, std::ios::cur, std::ios::in);
ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in);
buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in);
}
// read in the ASCII file and write back to the stream
std::strstreambuf sbuf(ulSize);
file >> &sbuf;
writer.Stream() << &sbuf;
}
file.close();
// remove temp file
fi.deleteFile();
}
Base::ifstream file(fi, std::ios::in | std::ios::binary);
if (file){
unsigned long ulSize = 0;
std::streambuf* buf = file.rdbuf();
if (buf) {
unsigned long ulCurr;
ulCurr = buf->pubseekoff(0, std::ios::cur, std::ios::in);
ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in);
buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in);
}
// read in the ASCII file and write back to the stream
std::strstreambuf sbuf(ulSize);
file >> &sbuf;
writer.Stream() << &sbuf;
else {
BRepTools::Write(myShape, writer.Stream());
}
file.close();
// remove temp file
fi.deleteFile();
}
}
@ -347,47 +354,55 @@ void PropertyPartShape::RestoreDocFile(Base::Reader &reader)
setValue(shape);
}
else {
BRep_Builder builder;
bool direct = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Part/General")->GetBool("DirectAccess", false);
if (!direct) {
BRep_Builder builder;
// create a temporary file and copy the content from the zip stream
Base::FileInfo fi(App::Application::getTempFileName());
// create a temporary file and copy the content from the zip stream
Base::FileInfo fi(App::Application::getTempFileName());
// read in the ASCII file and write back to the file stream
Base::ofstream file(fi, std::ios::out | std::ios::binary);
unsigned long ulSize = 0;
if (reader) {
std::streambuf* buf = file.rdbuf();
reader >> buf;
file.flush();
ulSize = buf->pubseekoff(0, std::ios::cur, std::ios::in);
}
file.close();
// read in the ASCII file and write back to the file stream
Base::ofstream file(fi, std::ios::out | std::ios::binary);
unsigned long ulSize = 0;
if (reader) {
std::streambuf* buf = file.rdbuf();
reader >> buf;
file.flush();
ulSize = buf->pubseekoff(0, std::ios::cur, std::ios::in);
}
file.close();
// Read the shape from the temp file, if the file is empty the stored shape was already empty.
// If it's still empty after reading the (non-empty) file there must occurred an error.
TopoDS_Shape shape;
if (ulSize > 0) {
if (!BRepTools::Read(shape, (const Standard_CString)fi.filePath().c_str(), builder)) {
// Note: Do NOT throw an exception here because if the tmp. created file could
// not be read it's NOT an indication for an invalid input stream 'reader'.
// We only print an error message but continue reading the next files from the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("BRep file '%s' with shape of '%s' seems to be empty\n",
fi.filePath().c_str(),obj->Label.getValue());
}
else {
Base::Console().Warning("Loaded BRep file '%s' seems to be empty\n", fi.filePath().c_str());
// Read the shape from the temp file, if the file is empty the stored shape was already empty.
// If it's still empty after reading the (non-empty) file there must occurred an error.
TopoDS_Shape shape;
if (ulSize > 0) {
if (!BRepTools::Read(shape, (const Standard_CString)fi.filePath().c_str(), builder)) {
// Note: Do NOT throw an exception here because if the tmp. created file could
// not be read it's NOT an indication for an invalid input stream 'reader'.
// We only print an error message but continue reading the next files from the
// stream...
App::PropertyContainer* father = this->getContainer();
if (father && father->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(father);
Base::Console().Error("BRep file '%s' with shape of '%s' seems to be empty\n",
fi.filePath().c_str(),obj->Label.getValue());
}
else {
Base::Console().Warning("Loaded BRep file '%s' seems to be empty\n", fi.filePath().c_str());
}
}
}
// delete the temp file
fi.deleteFile();
setValue(shape);
}
else {
BRep_Builder builder;
TopoDS_Shape shape;
BRepTools::Read(shape, reader, builder);
setValue(shape);
}
// delete the temp file
fi.deleteFile();
setValue(shape);
}
}

View File

@ -51,6 +51,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __GNUG__
#pragma implementation
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4244)
#endif
#include <boost/progress.hpp>
#include <boost/timer.hpp>

View File

@ -30,19 +30,17 @@
#ifdef FC_OS_WIN32
# define PointsExport __declspec(dllexport)
#else // for Linux
# define PointsExport
# define PointsExport
#endif
#ifdef _PreComp_
// here get the warnings of too long specifiers disabled (needed for VC6)
#ifdef _MSC_VER
# pragma warning( disable : 4251 )
# pragma warning( disable : 4503 )
# pragma warning( disable : 4275 )
# pragma warning( disable : 4786 ) // specifier longer then 255 chars
# pragma warning( disable : 4181 )
# pragma warning( disable : 4305 )
#endif
#ifdef _PreComp_
// standard
#include <stdio.h>
#include <assert.h>

View File

@ -19,6 +19,11 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef _MSC_VER
#pragma warning(disable : 4244)
#pragma warning(disable : 4800)
#endif
#include "svd_eigen_HH.hpp"
namespace KDL{

View File

@ -19,6 +19,11 @@
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifdef _MSC_VER
#pragma warning(disable : 4244)
#endif
#include <iostream>
#include <algorithm>
#include <cfloat>

View File

@ -19,6 +19,11 @@
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifdef _MSC_VER
#pragma warning(disable : 4244)
#endif
#include <iostream>
#include <Eigen/QR>

View File

@ -107,6 +107,7 @@
#include "ViewProviderSketch.h"
#include "DrawSketchHandler.h"
#include "TaskDlgEditSketch.h"
#include "TaskSketcherValidation.h"
// The first is used to point at a SoDatumLabel for some
// constraints, and at a SoMaterial for others...
@ -4151,7 +4152,7 @@ void ViewProviderSketch::attach(App::DocumentObject *pcFeat)
void ViewProviderSketch::setupContextMenu(QMenu *menu, QObject *receiver, const char *member)
{
menu->addAction(QObject::tr("Edit sketch"), receiver, member);
menu->addAction(tr("Edit sketch"), receiver, member);
}
bool ViewProviderSketch::setEdit(int ModNum)
@ -4165,8 +4166,8 @@ bool ViewProviderSketch::setEdit(int ModNum)
sketchDlg = 0; // another sketch left open its task panel
if (dlg && !sketchDlg) {
QMessageBox msgBox;
msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
msgBox.setText(tr("A dialog is already open in the task panel"));
msgBox.setInformativeText(tr("Do you want to close this dialog?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
@ -4178,8 +4179,21 @@ bool ViewProviderSketch::setEdit(int ModNum)
Sketcher::SketchObject* sketch = getSketchObject();
if (!sketch->evaluateConstraints()) {
QMessageBox::critical(Gui::getMainWindow(), tr("Invalid sketch"),
tr("The sketch is invalid and cannot be edited.\nUse the sketch validation tool."));
QMessageBox box(Gui::getMainWindow());
box.setIcon(QMessageBox::Critical);
box.setWindowTitle(tr("Invalid sketch"));
box.setText(tr("Do you want to open the sketch validation tool?"));
box.setInformativeText(tr("The sketch is invalid and cannot be edited."));
box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
box.setDefaultButton(QMessageBox::Yes);
switch (box.exec())
{
case QMessageBox::Yes:
Gui::Control().showDialog(new TaskSketcherValidation(getSketchObject()));
break;
default:
break;
}
return false;
}

View File

@ -62,6 +62,8 @@
#if defined(_MSC_VER)
#define strtoll _strtoi64
#pragma warning(disable : 4003)
#pragma warning(disable : 4065)
#endif
using namespace App;

View File

@ -179,6 +179,13 @@ class ParameterTestCase(unittest.TestCase):
self.failUnless(b.XLength==0,"X length > 0")
self.failUnless(b.YLength==0,"Y length > 0")
self.failUnless(b.ZLength==0,"Z length > 0")
self.failUnless(b.Center==FreeCAD.Vector(0,0,0),"Center is not at (0,0,0)")
self.failUnless(b.isInside(b.Center),"Center is not inside Bbox")
b.add(2,2,2)
self.failUnless(b.isInside(b.getIntersectionPoint(b.Center,FreeCAD.Vector(0,1,0))),"Intersection point is not inside Bbox")
self.failUnless(b.intersect(b),"Bbox doesn't intersect with itself")
self.failUnless(not b.intersected(FreeCAD.BoundBox(4,4,4,6,6,6)).isValid(),"Bbox should not intersect with Bbox outside")
self.failUnless(b.intersected(FreeCAD.BoundBox(-2,-2,-2,2,2,2)).Center == b.Center,"Bbox is not a full subset")
def testNesting(self):
# Parameter testing

View File

@ -79,41 +79,6 @@ private:
return Py::None();
}
};
/*
static PyObject* addTest(PyObject *self, PyObject *args)
{
char *pstr=0;
if (!PyArg_ParseTuple(args, "|s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
TestGui::UnitTestDialog* dlg = TestGui::UnitTestDialog::instance();
if (pstr)
dlg->addUnitTest(QString::fromLatin1(pstr));
dlg->show();
dlg->raise();
Py_Return;
}
static PyObject* setTest(PyObject *self, PyObject *args)
{
char *pstr=0;
if (!PyArg_ParseTuple(args, "|s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
TestGui::UnitTestDialog* dlg = TestGui::UnitTestDialog::instance();
if (pstr)
dlg->setUnitTest(QString::fromLatin1(pstr));
dlg->show();
dlg->raise();
Py_Return;
}
*/
/* registration table */
//static struct PyMethodDef TestGui_methods[] = {
// {"addTest", addTest, 1},
// {"setTest", setTest, 1},
// {NULL, NULL} /* end of table marker */
//};
void loadTestResource()
{
@ -130,10 +95,6 @@ void AppTestGuiExport initQtUnitGui()
// with the Python runtime system
(void)new UnitTestModule;
//if(PyType_Ready(&TestGui::UnitTestPy::Type) < 0) return;
//PyObject* pyModule = Py_InitModule("QtUnitGui", TestGui_methods); /* mod name, table ptr */
//union PyType_Object pyDlgType = {&TestGui::UnitTestPy::Type};
//PyModule_AddObject(pyModule, "UnitTest", pyDlgType.o);
Base::Console().Log("Loading GUI of Test module... done\n");
// add resources and reloads the translators

View File

@ -117,7 +117,22 @@ void UnitTestDialog::setProgressColor(const QColor& col)
*/
void UnitTestDialog::on_treeViewFailure_itemDoubleClicked(QTreeWidgetItem * item, int column)
{
QMessageBox::information(this, item->text(0), item->data(0, Qt::UserRole).toString());
QString text = item->data(0, Qt::UserRole).toString();
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Information);
msgBox.setWindowTitle(item->text(0));
msgBox.setDetailedText(text);
// truncate the visible text when it's too long
if (text.count(QLatin1Char('\n')) > 20) {
QStringList lines = text.split(QLatin1Char('\n'));
lines.erase(lines.begin()+20, lines.end());
text = lines.join(QLatin1String("\n"));
}
msgBox.setText(text);
msgBox.exec();
}
/**
@ -229,6 +244,14 @@ void UnitTestDialog::setUnitTest(const QString& unit)
}
}
/**
* Clears the unit tests.
*/
void UnitTestDialog::clearUnitTests()
{
this->comboTests->clear();
}
/**
* Returns the unit test.
*/

View File

@ -38,6 +38,7 @@ public:
void showErrorDialog(const char* title, const char* message);
void addUnitTest(const QString& unit);
void setUnitTest(const QString& unit);
void clearUnitTests();
QString getUnitTest() const;
void setStatusText(const QString& text);
void setProgressFraction(float fraction, const QString& = QString::null);

View File

@ -55,6 +55,8 @@ void UnitTestDialogPy::init_type()
add_varargs_method("setErrorCount",&UnitTestDialogPy::setErrorCount,"setErrorCount");
add_varargs_method("setRemainCount",&UnitTestDialogPy::setRemainCount,"setRemainCount");
add_varargs_method("updateGUI",&UnitTestDialogPy::updateGUI,"updateGUI");
add_varargs_method("addUnitTest",&UnitTestDialogPy::addUnitTest,"addUnitTest");
add_varargs_method("clearUnitTests",&UnitTestDialogPy::clearUnitTests,"clearUnitTests");
}
UnitTestDialogPy::UnitTestDialogPy()
@ -191,262 +193,25 @@ Py::Object UnitTestDialogPy::updateGUI(const Py::Tuple& args)
{
if (!PyArg_ParseTuple(args.ptr(), ""))
throw Py::Exception();
qApp->processEvents();
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
return Py::None();
}
//--------------------------------------------------------------------------
// Type structure
//--------------------------------------------------------------------------
PyTypeObject TestGui::UnitTestPy::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"TestGui.UnitTest", /*tp_name*/
sizeof(UnitTestPy), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
PyDestructor, /*tp_dealloc*/
0, /*tp_print*/
__getattr, /*tp_getattr*/
__setattr, /*tp_setattr*/
0, /*tp_compare*/
__repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call */
0, /*tp_str */
0, /*tp_getattro*/
0, /*tp_setattro*/
/* --- Functions to access object as input/output buffer ---------*/
0, /* tp_as_buffer */
/* --- Flags to define presence of optional/expanded features */
Py_TPFLAGS_HAVE_CLASS, /*tp_flags */
"About TestGui.UnitTest", /*tp_doc */
0, /*tp_traverse */
0, /*tp_clear */
0, /*tp_richcompare */
0, /*tp_weaklistoffset */
0, /*tp_iter */
0, /*tp_iternext */
0, /*tp_methods */
0, /*tp_members */
0, /*tp_getset */
&Base::PyObjectBase::Type, /*tp_base */
0, /*tp_dict */
0, /*tp_descr_get */
0, /*tp_descr_set */
0, /*tp_dictoffset */
0, /*tp_init */
0, /*tp_alloc */
UnitTestPy::PyMake, /*tp_new */
0, /*tp_free Low-level free-memory routine */
0, /*tp_is_gc For PyObject_IS_GC */
0, /*tp_bases */
0, /*tp_mro method resolution order */
0, /*tp_cache */
0, /*tp_subclasses */
0 /*tp_weaklist */
};
//--------------------------------------------------------------------------
// Methods structure
//--------------------------------------------------------------------------
PyMethodDef TestGui::UnitTestPy::Methods[] = {
PYMETHODEDEF(clearErrorList)
PYMETHODEDEF(insertError)
PYMETHODEDEF(setUnitTest)
PYMETHODEDEF(getUnitTest)
PYMETHODEDEF(setStatusText)
PYMETHODEDEF(setProgressFraction)
PYMETHODEDEF(errorDialog)
PYMETHODEDEF(setRunCount)
PYMETHODEDEF(setFailCount)
PYMETHODEDEF(setErrorCount)
PYMETHODEDEF(setRemainCount)
PYMETHODEDEF(updateGUI)
{NULL, NULL} /* Sentinel */
};
//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
TestGui::UnitTestPy::UnitTestPy(PyTypeObject *T)
: PyObjectBase(0, T)
Py::Object UnitTestDialogPy::addUnitTest(const Py::Tuple& args)
{
char *pstr;
if (!PyArg_ParseTuple(args.ptr(), "s", &pstr))
throw Py::Exception();
TestGui::UnitTestDialog* dlg = TestGui::UnitTestDialog::instance();
dlg->addUnitTest(QString::fromLatin1(pstr));
return Py::None();
}
PyObject *UnitTestPy::PyMake(PyTypeObject *ignored, PyObject *args, PyObject *kwds) // Python wrapper
Py::Object UnitTestDialogPy::clearUnitTests(const Py::Tuple& args)
{
return new UnitTestPy();
if (!PyArg_ParseTuple(args.ptr(), ""))
throw Py::Exception();
UnitTestDialog::instance()->clearUnitTests();
return Py::None();
}
//--------------------------------------------------------------------------
// destructor
//--------------------------------------------------------------------------
UnitTestPy::~UnitTestPy() // Everything handled in parent
{
}
//--------------------------------------------------------------------------
// UnitTestPy representation
//--------------------------------------------------------------------------
PyObject *UnitTestPy::_repr(void)
{
return Py_BuildValue("s", "UnitTest");
}
//--------------------------------------------------------------------------
// UnitTestPy Attributes
//--------------------------------------------------------------------------
PyObject *UnitTestPy::_getattr(char *attr) // __getattr__ function: note only need to handle new state
{
_getattr_up(PyObjectBase);
}
int UnitTestPy::_setattr(char *attr, PyObject *value) // __setattr__ function: note only need to handle new state
{
return PyObjectBase::_setattr(attr, value);
}
//--------------------------------------------------------------------------
// Python wrappers
//--------------------------------------------------------------------------
PYFUNCIMP_D(UnitTestPy,clearErrorList)
{
PY_TRY {
UnitTestDialog::instance()->clearErrorList();
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,insertError)
{
char *failure=0;
char *details=0;
if (!PyArg_ParseTuple(args, "ss", &failure,&details)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->insertError(QString::fromLatin1(failure),
QString::fromLatin1(details));
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setUnitTest)
{
char *pstr=0;
if (!PyArg_ParseTuple(args, "s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setUnitTest(QString::fromLatin1(pstr));
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,getUnitTest)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
return Py_BuildValue("s", (const char*)UnitTestDialog::instance()->getUnitTest().toAscii());
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setStatusText)
{
char *pstr=0;
if (!PyArg_ParseTuple(args, "s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setStatusText(QString::fromLatin1(pstr));
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setProgressFraction)
{
float fraction;
char* pColor=0;
if (!PyArg_ParseTuple(args, "f|s",&fraction, &pColor)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
if (pColor)
UnitTestDialog::instance()->setProgressFraction(fraction,QString::fromLatin1(pColor));
else
UnitTestDialog::instance()->setProgressFraction(fraction);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,errorDialog)
{
char *title=0;
char *message=0;
if (!PyArg_ParseTuple(args, "ss", &title, &message)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->showErrorDialog(title,message);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setRunCount)
{
int count;
if (!PyArg_ParseTuple(args, "i", &count)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setRunCount(count);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setFailCount)
{
int count;
if (!PyArg_ParseTuple(args, "i", &count)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setFailCount(count);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setErrorCount)
{
int count;
if (!PyArg_ParseTuple(args, "i", &count)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setErrorCount(count);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,setRemainCount)
{
int count;
if (!PyArg_ParseTuple(args, "i", &count)) // convert args: Python->C
return NULL; // NULL triggers exception
PY_TRY {
UnitTestDialog::instance()->setRemainCount(count);
Py_Return;
}PY_CATCH;
}
PYFUNCIMP_D(UnitTestPy,updateGUI)
{
PY_TRY {
qApp->processEvents();
Py_Return;
}PY_CATCH;
}

View File

@ -56,6 +56,8 @@ public:
Py::Object setErrorCount (const Py::Tuple&);
Py::Object setRemainCount (const Py::Tuple&);
Py::Object updateGUI (const Py::Tuple&);
Py::Object addUnitTest (const Py::Tuple&);
Py::Object clearUnitTests (const Py::Tuple&);
private:
typedef PyObject* (*method_varargs_handler)(PyObject *_self, PyObject *_args);
@ -63,43 +65,6 @@ private:
static PyObject *method_varargs_ext_handler(PyObject *_self, PyObject *_args);
};
//===========================================================================
// UnitTestPy - Python wrapper
//===========================================================================
class UnitTestPy :public Base::PyObjectBase
{
Py_Header;
protected:
~UnitTestPy();
public:
UnitTestPy(PyTypeObject *T = &Type);
static PyObject *PyMake(PyTypeObject *, PyObject *, PyObject *);
//---------------------------------------------------------------------
// python exports goes here +++++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------
virtual PyObject *_repr(void); // the representation
PyObject *_getattr(char *attr); // __getattr__ function
int _setattr(char *attr, PyObject *value); // __setattr__ function
PYFUNCDEF_D(UnitTestPy,clearErrorList)
PYFUNCDEF_D(UnitTestPy,insertError)
PYFUNCDEF_D(UnitTestPy,setUnitTest)
PYFUNCDEF_D(UnitTestPy,getUnitTest)
PYFUNCDEF_D(UnitTestPy,setStatusText)
PYFUNCDEF_D(UnitTestPy,setProgressFraction)
PYFUNCDEF_D(UnitTestPy,errorDialog)
PYFUNCDEF_D(UnitTestPy,setRunCount)
PYFUNCDEF_D(UnitTestPy,setFailCount)
PYFUNCDEF_D(UnitTestPy,setErrorCount)
PYFUNCDEF_D(UnitTestPy,setRemainCount)
PYFUNCDEF_D(UnitTestPy,updateGUI)
};
} //namespace TESTGUI_UNITTESTPY_H

View File

@ -70,7 +70,8 @@ def Test(s):
def testAll():
TestText(All())
r = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
r.run(All())
def testUnit():