Skip to content

Commit

Permalink
Attacher: add general purpose editor UI (python)
Browse files Browse the repository at this point in the history
Added as PartGui.AttachmentEditor, and Part_EditAttachment gui command
  • Loading branch information
DeepSOIC authored and wwmayer committed May 18, 2016
1 parent 836d5b1 commit 7f51976
Show file tree
Hide file tree
Showing 12 changed files with 1,378 additions and 53 deletions.
128 changes: 76 additions & 52 deletions src/Base/Interpreter.cpp
Expand Up @@ -92,49 +92,49 @@ void PyException::ReportException (void) const

SystemExitException::SystemExitException()
{
// Set exception message and code based upon the pthon sys.exit() code and/or message
// based upon the the following sys.exit() call semantics.
//
// Invocation | _exitCode | _sErrMsg
// ---------------- + --------- + --------
// sys.exit(int#) | int# | "System Exit"
// sys.exit(string) | 1 | string
// sys.exit() | 1 | "System Exit"

long int errCode = 1;
std::string errMsg = "System exit";
PyObject *type, *value, *traceback, *code;

PyGILStateLocker locker;
PyErr_Fetch(&type, &value, &traceback);
PyErr_NormalizeException(&type, &value, &traceback);

if (value) {
code = PyObject_GetAttrString(value, "code");
if (code != NULL && value != Py_None) {
Py_DECREF(value);
value = code;
}

if (PyInt_Check(value)) {
errCode = PyInt_AsLong(value);
}
else {
const char *str = PyString_AsString(value);
if (str)
errMsg = errMsg + ": " + str;
}
}

// Set exception message and code based upon the pthon sys.exit() code and/or message
// based upon the the following sys.exit() call semantics.
//
// Invocation | _exitCode | _sErrMsg
// ---------------- + --------- + --------
// sys.exit(int#) | int# | "System Exit"
// sys.exit(string) | 1 | string
// sys.exit() | 1 | "System Exit"

long int errCode = 1;
std::string errMsg = "System exit";
PyObject *type, *value, *traceback, *code;

PyGILStateLocker locker;
PyErr_Fetch(&type, &value, &traceback);
PyErr_NormalizeException(&type, &value, &traceback);

if (value) {
code = PyObject_GetAttrString(value, "code");
if (code != NULL && value != Py_None) {
Py_DECREF(value);
value = code;
}

if (PyInt_Check(value)) {
errCode = PyInt_AsLong(value);
}
else {
const char *str = PyString_AsString(value);
if (str)
errMsg = errMsg + ": " + str;
}
}

_sErrMsg = errMsg;
_exitCode = errCode;
_exitCode = errCode;
}

SystemExitException::SystemExitException(const SystemExitException &inst)
: Exception(inst), _exitCode(inst._exitCode)
{
}



// ---------------------------------------------------------

Expand Down Expand Up @@ -214,6 +214,30 @@ std::string InterpreterSingleton::runString(const char *sCmd)
}
}

Py::Object InterpreterSingleton::runString_returnObject(const char *sCmd)
{
PyObject *module, *dict, *presult; /* "exec code in d, d" */

PyGILStateLocker locker;
module = PP_Load_Module("__main__"); /* get module, init python */
if (module == NULL)
throw PyException(); /* not incref'd */
dict = PyModule_GetDict(module); /* get dict namespace */
if (dict == NULL)
throw PyException(); /* not incref'd */


presult = PyRun_String(sCmd, Py_eval_input, dict, dict); /* eval direct */
if (!presult) {
if (PyErr_ExceptionMatches(PyExc_SystemExit))
throw SystemExitException();
else
throw PyException();
}

return Py::Object(presult, true);
}

void InterpreterSingleton::systemExit(void)
{
/* This code is taken from the original Python code */
Expand Down Expand Up @@ -314,22 +338,22 @@ void InterpreterSingleton::runFile(const char*pxFileName, bool local)
Py_INCREF(dict); // avoid to further distinguish between local and global dict
}

if (PyDict_GetItemString(dict, "__file__") == NULL) {
PyObject *f = PyString_FromString(pxFileName);
if (f == NULL) {
fclose(fp);
Py_DECREF(dict);
return;
}
if (PyDict_SetItemString(dict, "__file__", f) < 0) {
Py_DECREF(f);
fclose(fp);
Py_DECREF(dict);
return;
}
Py_DECREF(f);
}

if (PyDict_GetItemString(dict, "__file__") == NULL) {
PyObject *f = PyString_FromString(pxFileName);
if (f == NULL) {
fclose(fp);
Py_DECREF(dict);
return;
}
if (PyDict_SetItemString(dict, "__file__", f) < 0) {
Py_DECREF(f);
fclose(fp);
Py_DECREF(dict);
return;
}
Py_DECREF(f);
}

PyObject *result = PyRun_File(fp, pxFileName, Py_file_input, dict, dict);
fclose(fp);
Py_DECREF(dict);
Expand Down
4 changes: 4 additions & 0 deletions src/Base/Interpreter.h
Expand Up @@ -34,6 +34,8 @@


#include <Python.h>
#include <CXX/Extensions.hxx>


#ifdef FC_OS_MACOSX
#undef toupper
Expand Down Expand Up @@ -159,6 +161,8 @@ class BaseExport InterpreterSingleton
//@{
/// Run a statement on the python interpreter and gives back a string with the representation of the result.
std::string runString(const char *psCmd);
/// Runs a string (expression) and returns object returned by expression.
Py::Object runString_returnObject(const char *sCmd);
/// Run a statement on the python interpreter and gives back a string with the representation of the result.
void runInteractiveString(const char *psCmd);
/// Run file (script) on the python interpreter
Expand Down
7 changes: 7 additions & 0 deletions src/Mod/Part/App/CMakeLists.txt
Expand Up @@ -287,6 +287,13 @@ SET(Part_Scripts
TestPartApp.py
MakeBottle.py
JoinFeatures.py
AttachmentEditor/__init__.py
AttachmentEditor/Commands.py
AttachmentEditor/DepGraphTools.py
AttachmentEditor/FrozenClass.py
AttachmentEditor/TaskAttachmentEditor.py
AttachmentEditor/TaskAttachmentEditor.ui
AttachmentEditor/TempoVis.py
)

add_library(Part SHARED ${Part_SRCS})
Expand Down
100 changes: 100 additions & 0 deletions src/Mod/Part/AttachmentEditor/Commands.py
@@ -0,0 +1,100 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2016 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library 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 library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/

from __future__ import absolute_import

import FreeCAD as App
from PySide import QtCore

def editAttachment(feature = None,
take_selection = False,
create_transaction = True,
callback_OK = None,
callback_Cancel = None,
callback_Apply = None):
'''Opens attachment editing dialog.
editAttachment(feature = None,
take_selection = False,
create_transaction = True,
callback_OK = None,
callback_Cancel = None,
callback_Apply = None)
feature: object to attach/modify. If None is supplied, the object is taken from
selection.
take_selection: if True, current selection is filled into first references (but only
if object to be attached doesn't have any references already)
create_transaction = if False, no undo transation operations will be done by the
dialog (consequently, canceling the dialog will not reset the feature to original
state).
callback_OK: function to be called upon OK. Invoked after writing values to feature,
committing transaction and closing the dialog.
callback_Cancel: called after closing the dialog and aborting transaction.
callback_Apply: invoked after writing values to feature.'''

import AttachmentEditor.TaskAttachmentEditor as TaskAttachmentEditor
global taskd # exposing to outside, for ease of debugging
if feature is None:
feature = Gui.Selection.getSelectionEx()[0].Object

try:
taskd = TaskAttachmentEditor.AttachmentEditorTaskPanel(feature,
take_selection= take_selection,
create_transaction= create_transaction,
callback_OK= callback_OK,
callback_Cancel= callback_Cancel,
callback_Apply= callback_Apply)
Gui.Control.showDialog(taskd)
except TaskAttachmentEditor.CancelError:
pass


class CommandEditAttachment:
'Command to edit attachment'
def GetResources(self):
return {'MenuText': QtCore.QT_TRANSLATE_NOOP("AttachmentEditor","Attachment..."),
'Accel': "",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("AttachmentEditor","Edit attachment of selected object.")}

def Activated(self):
try:
editAttachment()
except Exception as err:
from PySide import QtGui
mb = QtGui.QMessageBox()
mb.setIcon(mb.Icon.Warning)
mb.setText(err.message)
mb.setWindowTitle("Error")
mb.exec_()

def IsActive(self):
sel = Gui.Selection.getSelectionEx()
if len(sel) == 1:
if hasattr(sel[0].Object,"Placement"):
return True
return False

if App.GuiUp:
global command_instance
import FreeCADGui as Gui
command_instance = CommandEditAttachment()
Gui.addCommand('Part_EditAttachment', command_instance)
82 changes: 82 additions & 0 deletions src/Mod/Part/AttachmentEditor/DepGraphTools.py
@@ -0,0 +1,82 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2016 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library 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 library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/

import FreeCAD as App

def getAllDependencies(feat):
'''getAllDependencies(feat): gets all features feat depends on, directly or indirectly.
Returns a list, with deepest dependencies last. feat is not included in the list, except
if the feature depends on itself (dependency loop).'''
list_traversing_now = [feat]
set_of_deps = set()
list_of_deps = []

while len(list_traversing_now) > 0:
list_to_be_traversed_next = []
for feat in list_traversing_now:
for dep in feat.OutList:
if not (dep in set_of_deps):
set_of_deps.add(dep)
list_of_deps.append(dep)
list_to_be_traversed_next.append(dep)

list_traversing_now = list_to_be_traversed_next

return list_of_deps

def getAllDependent(feat):
'''getAllDependent(feat): gets all features that depend on feat, directly or indirectly.
Returns a list, with deepest dependencies last. feat is not included in the list, except
if the feature depends on itself (dependency loop).'''
list_traversing_now = [feat]
set_of_deps = set()
list_of_deps = []

while len(list_traversing_now) > 0:
list_to_be_traversed_next = []
for feat in list_traversing_now:
for dep in feat.InList:
if not (dep in set_of_deps):
set_of_deps.add(dep)
list_of_deps.append(dep)
list_to_be_traversed_next.append(dep)

list_traversing_now = list_to_be_traversed_next

return list_of_deps

def isContainer(obj):
'''isContainer(obj): returns True if obj is an object container, such as
Group, Part, Body. The important characterisic of an object being a
container is its action on visibility of linked objects. E.g. a
Part::Compound is not a group, because it does not affect visibility
of originals. Documents are considered containers, too.'''

if obj.isDerivedFrom("App::DocumentObjectGroup"):
return True
if obj.isDerivedFrom("PartDesign::Body"):
return True
if obj.isDerivedFrom("App::Origin"):
return True
if obj.isDerivedFrom('App::Document'):
return True

0 comments on commit 7f51976

Please sign in to comment.