diff --git a/configure.ac b/configure.ac index 05010ef14..4f94456af 100644 --- a/configure.ac +++ b/configure.ac @@ -1056,6 +1056,7 @@ src/Mod/Sandbox/App/Makefile src/Mod/Sandbox/Gui/Makefile src/Mod/Surfaces/Makefile src/Mod/Ship/Makefile +src/Mod/OpenSCAD/Makefile src/Tools/Makefile src/Tools/_TEMPLATE_/Makefile src/Tools/_TEMPLATE_/App/Makefile diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6d440389f..555abac59 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,14 +16,11 @@ if(FREECAD_BUILD_TEMPLATE) add_subdirectory(Tools/_TEMPLATE_) endif(FREECAD_BUILD_TEMPLATE) -if(FREECAD_MAINTAINERS_BUILD) - add_subdirectory(Doc) -endif(FREECAD_MAINTAINERS_BUILD) +add_subdirectory(Doc) if(FREECAD_MAINTAINERS_BUILD AND WIN32) #add_subdirectory(WindowsInstaller) endif(FREECAD_MAINTAINERS_BUILD AND WIN32) - INSTALL(FILES Doc/Start_Page.html Doc/freecad.qhc Doc/freecad.qch DESTINATION ${CMAKE_INSTALL_DOCDIR} ) diff --git a/src/Doc/CMakeLists.txt b/src/Doc/CMakeLists.txt index 46fdb57b0..f2639f2a7 100644 --- a/src/Doc/CMakeLists.txt +++ b/src/Doc/CMakeLists.txt @@ -49,7 +49,7 @@ if(DOXYGEN_FOUND) STRING(REGEX REPLACE ";" " " DOXYGEN_EXCLUDE_LIST "${DOXYGEN_EXCLUDE_DIR}") - SET(DOXYGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/Doc/SourceDocu) + SET(DOXYGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/doc/SourceDocu) SET(DOXYGEN_IMAGE_PATH ${CMAKE_SOURCE_DIR}/src/Gui/Icons) SET(DOXYGEN_LAYOUT_FILE ${CMAKE_SOURCE_DIR}/src/Doc/FreecadDoxygenLayout.xml) @@ -66,8 +66,8 @@ if(DOXYGEN_FOUND) if( FREECAD_MAINTAINERS_BUILD ) ADD_CUSTOM_TARGET(SourceDocu ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/BuildDevDoc.cfg - COMMAND ${QT_HELPCOMPILER_EXECUTABLE} "\"${CMAKE_BINARY_DIR}/Doc/SourceDocu/html/index.qhp\"" - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/Doc/SourceDocu/html/index.qch ${CMAKE_BINARY_DIR}/Doc/FreeCADSource.qch + COMMAND ${QT_HELPCOMPILER_EXECUTABLE} "\"${CMAKE_BINARY_DIR}/doc/SourceDocu/html/index.qhp\"" + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/doc/SourceDocu/html/index.qch ${CMAKE_BINARY_DIR}/doc/FreeCADSource.qch WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/BuildDevDoc.cfg ) @@ -77,7 +77,7 @@ if(DOXYGEN_FOUND) ${CMAKE_SOURCE_DIR}/src/Tools/wiki2qhelp.py -c ${QT_HELPCOMPILER_EXECUTABLE} -g ${QT_COLLECTIOMGENERATOR_EXECUTABLE} - -o ${CMAKE_BINARY_DIR}/Doc + -o ${CMAKE_BINARY_DIR}/doc ) else( FREECAD_MAINTAINERS_BUILD ) diff --git a/src/Gui/Icons/Makefile.am b/src/Gui/Icons/Makefile.am index 66c1c3548..b3dfcfc34 100644 --- a/src/Gui/Icons/Makefile.am +++ b/src/Gui/Icons/Makefile.am @@ -69,6 +69,12 @@ EXTRA_DIST = \ accessories-text-editor.svg \ help-browser.svg \ spaceball_button.svg \ + SpNav-PanLR.png \ + SpNav-PanUD.png \ + SpNav-Roll.png \ + SpNav-Spin.png \ + SpNav-Tilt.png \ + SpNav-Zoom.png \ view-unselectable.svg \ view-refresh.svg \ view-measurement.svg \ diff --git a/src/Gui/Makefile.am b/src/Gui/Makefile.am index c714f4913..e82edc126 100644 --- a/src/Gui/Makefile.am +++ b/src/Gui/Makefile.am @@ -13,6 +13,7 @@ BUILT_SOURCES=\ moc_DlgCommandsImp.cpp \ moc_DlgCustomizeImp.cpp \ moc_DlgCustomizeSpaceball.cpp \ + moc_DlgCustomizeSpNavSettings.cpp \ moc_DlgDisplayPropertiesImp.cpp \ moc_DlgEditorImp.cpp \ moc_DlgGeneralImp.cpp \ @@ -84,6 +85,7 @@ BUILT_SOURCES=\ ui_DlgAuthorization.h \ ui_DlgChooseIcon.h \ ui_DlgCommands.h \ + ui_DlgCustomizeSpNavSettings.h \ ui_DlgDisplayProperties.h \ ui_DlgEditor.h \ ui_DlgInputDialog.h \ @@ -133,6 +135,7 @@ libFreeCADGui_la_UI=\ DlgAuthorization.ui \ DlgChooseIcon.ui \ DlgCommands.ui \ + DlgCustomizeSpNavSettings.ui \ DlgDisplayProperties.ui \ DlgEditor.ui \ DlgGeneral.ui \ @@ -208,6 +211,8 @@ libFreeCADGui_la_SOURCES=\ DlgCustomizeImp.h \ DlgCustomizeSpaceball.cpp \ DlgCustomizeSpaceball.h \ + DlgCustomizeSpNavSettings.cpp \ + DlgCustomizeSpNavSettings.h \ DlgDisplayPropertiesImp.cpp \ DlgDisplayPropertiesImp.h \ DlgEditorImp.cpp \ diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 2c62d316a..f82b27063 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -59,7 +59,29 @@ using namespace Gui; namespace Gui { -static size_t promptLength = 4; //< length of prompt string: ">>> " or "... ", in either case 4 characters +static const QChar promptEnd( QLatin1Char(' ') ); //< char for detecting prompt end + +inline int promptLength( const QString &lineStr ) + { return lineStr.indexOf( promptEnd ) + 1; } + +inline QString stripPromptFrom( const QString &lineStr ) + { return lineStr.mid( promptLength(lineStr) ); } + +/** + * cursorBeyond checks if cursor is at a valid position to accept keyEvents. + * @param cursor - cursor to check + * @param limit - cursor that marks the begin of the input region + * @param shift - offset for shifting the limit for non-selection cursors [default: 0] + * @return true if a keyEvent is ok at cursor's position, false otherwise + */ +inline bool cursorBeyond( const QTextCursor &cursor, const QTextCursor &limit, int shift = 0 ) +{ + int pos = limit.position(); + if (cursor.hasSelection()) + return (cursor.selectionStart() >= pos && cursor.selectionEnd() >= pos); + else + return cursor.position() >= (pos + shift); +} struct PythonConsoleP { @@ -341,7 +363,7 @@ void InteractiveInterpreter::clearBuffer() * Constructs a PythonConsole which is a child of 'parent'. */ PythonConsole::PythonConsole(QWidget *parent) - : TextEdit(parent), WindowParameter( "Editor" ) + : TextEdit(parent), WindowParameter( "Editor" ), _sourceDrain(NULL) { d = new PythonConsoleP(); d->interactive = false; @@ -445,7 +467,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) QTextCursor cursor = this->textCursor(); QTextCursor inputLineBegin = this->inputBegin(); - if (cursor < inputLineBegin) + if (!cursorBeyond( cursor, inputLineBegin )) { /** * The cursor is placed not on the input line (or within the prompt string) @@ -460,6 +482,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Return: case Qt::Key_Enter: case Qt::Key_Escape: + case Qt::Key_Backspace: this->moveCursor( QTextCursor::End ); break; @@ -488,19 +511,20 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) * - show call tips on period */ QTextBlock inputBlock = inputLineBegin.block(); //< get the last paragraph's text - QString inputLine = inputBlock.text().mid(promptLength); //< and skip prompt characters + QString inputLine = inputBlock.text(); + QString inputStrg = stripPromptFrom( inputLine ); switch (e->key()) { case Qt::Key_Escape: { - // disable current input line - i.e. put it to history but don't execute it. - if (!inputLine.isEmpty()) + // disable current input string - i.e. put it to history but don't execute it. + if (!inputStrg.isEmpty()) { - d->history.append( QLatin1String("# ") + inputLine ); //< put line to history ... - inputLineBegin.insertText( QString::fromAscii("# ") ); //< but comment it on console + d->history.append( QLatin1String("# ") + inputStrg ); //< put commented string to history ... + inputLineBegin.insertText( QString::fromAscii("# ") ); //< and comment it on console setTextCursor( inputLineBegin ); - printPrompt(d->interpreter->hasPendingInput() //< print adequate prompt + printPrompt(d->interpreter->hasPendingInput() //< print adequate prompt ? PythonConsole::Incomplete : PythonConsole::Complete); } @@ -509,8 +533,8 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Return: case Qt::Key_Enter: { - runSource( inputLine ); //< commit input line - d->history.append( inputLine ); //< put statement to history + d->history.append( inputStrg ); //< put statement to history + runSource( inputStrg ); //< commit input string } break; case Qt::Key_Period: @@ -518,14 +542,14 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) // analyse context and show available call tips int contextLength = cursor.position() - inputLineBegin.position(); TextEdit::keyPressEvent(e); - d->callTipsList->showTips( inputLine.left( contextLength ) ); + d->callTipsList->showTips( inputStrg.left( contextLength ) ); } break; case Qt::Key_Home: { QTextCursor::MoveMode mode = (e->modifiers() & Qt::ShiftModifier)? QTextCursor::KeepAnchor /* else */ : QTextCursor::MoveAnchor; - cursor.setPosition( inputBlock.position() + promptLength, mode ); + cursor.setPosition( inputLineBegin.position(), mode ); setTextCursor( cursor ); ensureCursorVisible(); } break; @@ -533,7 +557,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Up: { // if possible, move back in history - if (d->history.prev( inputLine )) + if (d->history.prev( inputStrg )) { overrideCursor( d->history.value() ); } restartHistory = false; } break; @@ -561,7 +585,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Backspace: { - if (cursor > inputLineBegin) + if (cursorBeyond( cursor, inputLineBegin, +1 )) { TextEdit::keyPressEvent(e); } } break; @@ -576,7 +600,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) { d->callTipsList->validateCursor(); } // disable history restart if input line changed - restartHistory &= (inputLine != inputBlock.text().mid(promptLength)); + restartHistory &= (inputLine != inputBlock.text()); } // any cursor move resets the history to its latest item. if (restartHistory) @@ -623,37 +647,40 @@ void PythonConsole::printPrompt(PythonConsole::Prompt mode) d->error = QString::null; } - // Append the prompt string - QTextCursor cursor = textCursor(); - cursor.beginEditBlock(); - cursor.movePosition(QTextCursor::End); - QTextBlock block = cursor.block(); - - // Python's print command appends a trailing '\n' to the system output. - // In this case, however, we should not add a new text block. We force - // the current block to be normal text (user state = 0) to be highlighted - // correctly and append the '>>> ' or '... ' to this block. - if (block.length() > 1) - cursor.insertBlock(cursor.blockFormat(), cursor.charFormat()); - else - block.setUserState(0); - - switch (mode) + if (mode != PythonConsole::Special) { - case PythonConsole::Incomplete: - cursor.insertText(QString::fromAscii("... ")); - break; - case PythonConsole::Complete: - cursor.insertText(QString::fromAscii(">>> ")); - break; - default: - break; - } - cursor.endEditBlock(); + // Append the prompt string + QTextCursor cursor = textCursor(); + cursor.beginEditBlock(); + cursor.movePosition(QTextCursor::End); + QTextBlock block = cursor.block(); + + // Python's print command appends a trailing '\n' to the system output. + // In this case, however, we should not add a new text block. We force + // the current block to be normal text (user state = 0) to be highlighted + // correctly and append the '>>> ' or '... ' to this block. + if (block.length() > 1) + cursor.insertBlock(cursor.blockFormat(), cursor.charFormat()); + else + block.setUserState(0); + + switch (mode) + { + case PythonConsole::Incomplete: + cursor.insertText(QString::fromAscii("... ")); + break; + case PythonConsole::Complete: + cursor.insertText(QString::fromAscii(">>> ")); + break; + default: + break; + } + cursor.endEditBlock(); - // move cursor to the end - cursor.movePosition(QTextCursor::End); - setTextCursor(cursor); + // move cursor to the end + cursor.movePosition(QTextCursor::End); + setTextCursor(cursor); + } } /** @@ -683,6 +710,17 @@ void PythonConsole::appendOutput(const QString& output, int state) */ void PythonConsole::runSource(const QString& line) { + /** + * Check if there's a "source drain", which want's to consume the source in another way then just executing it. + * If so, put the source to the drain and emit a signal to notify the consumer, whoever this may be. + */ + if (this->_sourceDrain) + { + *this->_sourceDrain = line; + Q_EMIT pendingSource(); + return; + } + bool incomplete = false; Base::PyGILStateLocker lock; PyObject* default_stdout = PySys_GetObject("stdout"); @@ -692,8 +730,11 @@ void PythonConsole::runSource(const QString& line) d->interactive = true; try { + d->history.markScratch(); //< mark current history position ... // launch the command now incomplete = d->interpreter->push(line.toUtf8()); + if (!incomplete) + { d->history.doScratch(); } //< ... and scratch history entries that might have been added by executing the line. setFocus(); // if focus was lost } catch (const Base::SystemExitException&) { @@ -923,7 +964,8 @@ QTextCursor PythonConsole::inputBegin( void ) const QTextCursor inputLineBegin( this->textCursor() ); inputLineBegin.movePosition( QTextCursor::End ); inputLineBegin.movePosition( QTextCursor::StartOfLine ); - inputLineBegin.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptLength ); + // ... and move cursor right beyond the prompt. + inputLineBegin.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptLength( inputLineBegin.block().text() ) ); return inputLineBegin; } @@ -948,10 +990,7 @@ QMimeData * PythonConsole::createMimeDataFromSelection () const int pos = b.position(); if ( pos >= s && pos <= e ) { if (b.userState() > -1 && b.userState() < pythonSyntax->maximumUserState()) { - QString line = b.text(); - // and skip the prompt characters consisting of either ">>> " or "... " - line = line.mid(promptLength); - lines << line; + lines << stripPromptFrom( b.text() ); } } } @@ -1020,8 +1059,7 @@ void PythonConsole::runSourceFromMimeData(const QString& source) QString select = cursor.selectedText(); cursor.removeSelectedText(); last = last + select; - line = cursor.block().text(); - line = line.mid(promptLength); + line = stripPromptFrom( cursor.block().text() ); } // put statement to the history @@ -1073,12 +1111,10 @@ void PythonConsole::runSourceFromMimeData(const QString& source) void PythonConsole::overrideCursor(const QString& txt) { // Go to the last line and the fourth position, right after the prompt - QTextCursor cursor = textCursor(); - QTextBlock block = cursor.block(); - cursor.movePosition(QTextCursor::End); - cursor.movePosition(QTextCursor::StartOfLine); - cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength); - cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, block.text().length()); + QTextCursor cursor = this->inputBegin(); + int blockLength = this->textCursor().block().text().length(); + + cursor.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, blockLength ); //<< select text to override cursor.removeSelectedText(); cursor.insertText(txt); // move cursor to the end @@ -1090,12 +1126,7 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) { QMenu menu(this); QAction *a; - // construct reference cursor at begin of input line ... - QTextCursor cursor = this->textCursor(); - QTextCursor inputLineBegin = cursor; - inputLineBegin.movePosition(QTextCursor::End); - inputLineBegin.movePosition(QTextCursor::StartOfLine); - inputLineBegin.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength); + bool mayPasteHere = cursorBeyond( this->textCursor(), this->inputBegin() ); a = menu.addAction(tr("&Copy"), this, SLOT(copy()), Qt::CTRL+Qt::Key_C); a->setEnabled(textCursor().hasSelection()); @@ -1113,7 +1144,7 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) a = menu.addAction(tr("&Paste"), this, SLOT(paste()), Qt::CTRL+Qt::Key_V); const QMimeData *md = QApplication::clipboard()->mimeData(); - a->setEnabled(cursor >= inputLineBegin && md && canInsertFromMimeData(md)); + a->setEnabled( mayPasteHere && md && canInsertFromMimeData(md)); a = menu.addAction(tr("Select All"), this, SLOT(selectAll()), Qt::CTRL+Qt::Key_A); a->setEnabled(!document()->isEmpty()); @@ -1195,6 +1226,20 @@ void PythonConsole::onCopyCommand() d->type = PythonConsoleP::Normal; } +QString PythonConsole::readline( void ) +{ + QEventLoop loop; + QString inputBuffer; + + printPrompt( PythonConsole::Special ); + this->_sourceDrain = &inputBuffer; //< enable source drain ... + // ... and wait until we get notified about pendingSource + QObject::connect( this, SIGNAL(pendingSource()), &loop, SLOT(quit()) ); + loop.exec(); + this->_sourceDrain = NULL; //< disable source drain + return inputBuffer.append(QChar::fromAscii('\n')); //< pass a newline here, since the readline-caller may need it! +} + // --------------------------------------------------------------------- PythonConsoleHighlighter::PythonConsoleHighlighter(QObject* parent) @@ -1245,6 +1290,7 @@ void PythonConsoleHighlighter::colorChanged(const QString& type, const QColor& c // --------------------------------------------------------------------- ConsoleHistory::ConsoleHistory() +: _scratchBegin(0) { _it = _history.end(); } @@ -1345,6 +1391,28 @@ void ConsoleHistory::restart( void ) _it = _history.end(); } +/** + * markScratch stores the current end index of the history list. + * Note: with simply remembering a start index, it does not work to nest scratch regions. + * However, just replace the index keeping by a stack - in case this is be a concern. + */ +void ConsoleHistory::markScratch( void ) +{ + _scratchBegin = _history.length(); +} + +/** + * doScratch removes the tail of the history list, starting from the index marked lately. + */ +void ConsoleHistory::doScratch( void ) +{ + if (_scratchBegin < _history.length()) + { + _history.erase( _history.begin() + _scratchBegin, _history.end() ); + this->restart(); + } +} + // ----------------------------------------------------- /* TRANSLATOR Gui::PythonInputField */ diff --git a/src/Gui/PythonConsole.h b/src/Gui/PythonConsole.h index ceda0a5ec..b949894d9 100644 --- a/src/Gui/PythonConsole.h +++ b/src/Gui/PythonConsole.h @@ -79,10 +79,13 @@ public: void append(const QString &inputLine); const QStringList& values() const; void restart(); + void markScratch( void ); + void doScratch( void ); private: QStringList _history; QStringList::ConstIterator _it; + int _scratchBegin; QString _prefix; }; @@ -99,7 +102,8 @@ public: enum Prompt { Complete = 0, Incomplete = 1, - Flush = 2 + Flush = 2, + Special = 3 }; PythonConsole(QWidget *parent = 0); @@ -107,6 +111,7 @@ public: void OnChange( Base::Subject &rCaller,const char* rcReason ); void printStatement( const QString& cmd ); + QString readline( void ); public Q_SLOTS: void onSaveHistoryAs(); @@ -126,7 +131,7 @@ protected: void dragEnterEvent ( QDragEnterEvent * e ); void dragMoveEvent ( QDragMoveEvent * e ); void changeEvent ( QEvent * e ); - void mouseReleaseEvent( QMouseEvent * e ); + void mouseReleaseEvent( QMouseEvent * e ); void overrideCursor(const QString& txt); @@ -146,6 +151,9 @@ private: void runSourceFromMimeData(const QString&); void appendOutput(const QString&, int); +Q_SIGNALS: + void pendingSource( void ); + private: struct PythonConsoleP* d; @@ -154,6 +162,7 @@ private: private: PythonConsoleHighlighter* pythonSyntax; + QString *_sourceDrain; }; /** diff --git a/src/Gui/PythonConsolePy.cpp b/src/Gui/PythonConsolePy.cpp index 5e9d18817..b9fe2a5f0 100644 --- a/src/Gui/PythonConsolePy.cpp +++ b/src/Gui/PythonConsolePy.cpp @@ -317,16 +317,5 @@ Py::Object PythonStdin::repr() Py::Object PythonStdin::readline(const Py::Tuple& args) { - if (console) - console->onFlush(); - timer->stop(); - QEventLoop loop; - QObject::connect(editField, SIGNAL(textEntered()), &loop, SLOT(quit())); - editField->clear(); - editField->show(); - editField->setFocus(); - loop.exec(); - QString txt = editField->getText(); - timer->start(); - return Py::String((const char*)txt.toAscii()); + return Py::String( (const char *)console->readline().toAscii() ); } diff --git a/src/Mod/Makefile.am b/src/Mod/Makefile.am index e018e56c7..246e76ba4 100644 --- a/src/Mod/Makefile.am +++ b/src/Mod/Makefile.am @@ -1,5 +1,5 @@ #SUBDIRS=Part Mesh Points Raytracing Image Drawing Complete Draft Test TemplatePyMod -SUBDIRS=Points Complete Draft Test TemplatePyMod Web Start Idf Arch Surfaces Ship OpenSCAD +SUBDIRS=Points Complete Draft Test TemplatePyMod Web Start Idf #if HAVE_OPENCV SUBDIRS += Image @@ -10,7 +10,7 @@ SUBDIRS += Mesh #endif if HAVE_OPENCASCADE -SUBDIRS += Part Import PartDesign Raytracing Drawing +SUBDIRS += Part Import PartDesign Raytracing Drawing Arch Surfaces Ship OpenSCAD endif if HAVE_EIGEN3 diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp index e14406e92..42d82b923 100644 --- a/src/Mod/PartDesign/App/FeatureChamfer.cpp +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp @@ -52,11 +52,9 @@ Chamfer::Chamfer() short Chamfer::mustExecute() const { - if (Placement.isTouched() || Base.isTouched() || Size.isTouched()) + if (Placement.isTouched() || Size.isTouched()) return 1; - if (Base.getValue() && Base.getValue()->isTouched()) - return 1; - return 0; + return DressUp::mustExecute(); } App::DocumentObjectExecReturn *Chamfer::execute(void) diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index da69c80ed..b957fedfc 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -41,6 +41,14 @@ DressUp::DressUp() ADD_PROPERTY(Base,(0)); } +short DressUp::mustExecute() const +{ + if (Base.getValue() && Base.getValue()->isTouched()) + return 1; + return PartDesign::Feature::mustExecute(); +} + + void DressUp::positionByBase(void) { Part::Feature *base = static_cast(Base.getValue()); diff --git a/src/Mod/PartDesign/App/FeatureDressUp.h b/src/Mod/PartDesign/App/FeatureDressUp.h index 44236f26a..52aa6b335 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.h +++ b/src/Mod/PartDesign/App/FeatureDressUp.h @@ -39,6 +39,7 @@ public: App::PropertyLinkSub Base; + short mustExecute() const; /// updates the Placement property from the Placement of Base void positionByBase(void); diff --git a/src/Mod/PartDesign/App/FeatureFace.cpp b/src/Mod/PartDesign/App/FeatureFace.cpp index e2786b069..5bf37da33 100644 --- a/src/Mod/PartDesign/App/FeatureFace.cpp +++ b/src/Mod/PartDesign/App/FeatureFace.cpp @@ -62,7 +62,7 @@ short Face::mustExecute() const { if (Sources.isTouched()) return 1; - return 0; + return Part::Part2DObject::mustExecute(); } App::DocumentObjectExecReturn *Face::execute(void) diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp index 3b9470c51..8f9d8d3e8 100644 --- a/src/Mod/PartDesign/App/FeatureFillet.cpp +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp @@ -49,11 +49,9 @@ Fillet::Fillet() short Fillet::mustExecute() const { - if (Placement.isTouched() || Base.isTouched() || Radius.isTouched()) + if (Placement.isTouched() || Radius.isTouched()) return 1; - if (Base.getValue() && Base.getValue()->isTouched()) - return 1; - return 0; + return DressUp::mustExecute(); } App::DocumentObjectExecReturn *Fillet::execute(void) diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 1cf17541d..baa60683e 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -48,7 +48,7 @@ using namespace PartDesign; namespace PartDesign { -PROPERTY_SOURCE(PartDesign::Groove, PartDesign::SketchBased) +PROPERTY_SOURCE(PartDesign::Groove, PartDesign::Subtractive) Groove::Groove() { @@ -63,7 +63,6 @@ Groove::Groove() short Groove::mustExecute() const { if (Placement.isTouched() || - Sketch.isTouched() || ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || @@ -71,7 +70,7 @@ short Groove::mustExecute() const Midplane.isTouched() || Reversed.isTouched()) return 1; - return 0; + return Subtractive::mustExecute(); } App::DocumentObjectExecReturn *Groove::execute(void) diff --git a/src/Mod/PartDesign/App/FeatureGroove.h b/src/Mod/PartDesign/App/FeatureGroove.h index 5f17ce092..ec13362d3 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.h +++ b/src/Mod/PartDesign/App/FeatureGroove.h @@ -25,12 +25,12 @@ #define PARTDESIGN_Groove_H #include -#include "FeatureSketchBased.h" +#include "FeatureSubtractive.h" namespace PartDesign { -class PartDesignExport Groove : public SketchBased +class PartDesignExport Groove : public Subtractive { PROPERTY_HEADER(PartDesign::Groove); diff --git a/src/Mod/PartDesign/App/FeatureHole.cpp b/src/Mod/PartDesign/App/FeatureHole.cpp index 25c7483e0..c16d6a7f7 100644 --- a/src/Mod/PartDesign/App/FeatureHole.cpp +++ b/src/Mod/PartDesign/App/FeatureHole.cpp @@ -53,7 +53,7 @@ const char* Hole::TypeEnums[] = {"Dimension","UpToLast","UpToFirst",NULL}; const char* Hole::HoleTypeEnums[]= {"Simple","Counterbore","Countersunk",NULL}; const char* Hole::ThreadEnums[] = {"None","Metric","MetricFine",NULL}; -PROPERTY_SOURCE(PartDesign::Hole, PartDesign::SketchBased) +PROPERTY_SOURCE(PartDesign::Hole, PartDesign::Subtractive) Hole::Hole() { @@ -72,7 +72,7 @@ Hole::Hole() // if (Sketch.isTouched() || // Length.isTouched()) // return 1; -// return 0; +// return Subtractive::mustExecute(); //} App::DocumentObjectExecReturn *Hole::execute(void) @@ -134,6 +134,8 @@ App::DocumentObjectExecReturn *Hole::execute(void) //if (PrismMaker.IsDone()) { // // if the sketch has a support fuse them to get one result object (PAD!) // if (SupportObject) { + // // Set the subtractive shape property for later usage in e.g. pattern + // this->SubShape.setValue(PrismMaker.Shape()); // const TopoDS_Shape& support = SupportObject->Shape.getValue(); // if (support.IsNull()) // return new App::DocumentObjectExecReturn("Support shape is invalid"); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 8335668ae..cc7f18ebe 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -68,14 +68,13 @@ Pad::Pad() short Pad::mustExecute() const { if (Placement.isTouched() || - Sketch.isTouched() || Length.isTouched() || Midplane.isTouched() || Reversed.isTouched() || Length2.isTouched() || FaceName.isTouched()) return 1; - return 0; + return Additive::mustExecute(); } App::DocumentObjectExecReturn *Pad::execute(void) diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index beec62191..074c7b00f 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -56,7 +56,7 @@ using namespace PartDesign; const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst","ThroughAll","UpToFace",NULL}; -PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::SketchBased) +PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::Subtractive) Pocket::Pocket() { @@ -69,11 +69,10 @@ Pocket::Pocket() short Pocket::mustExecute() const { if (Placement.isTouched() || - Sketch.isTouched() || Length.isTouched() || FaceName.isTouched()) return 1; - return 0; + return Subtractive::mustExecute(); } App::DocumentObjectExecReturn *Pocket::execute(void) @@ -255,8 +254,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void) return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pocket feature"); } - // TODO: Set the subtractive shape property for later usage in e.g. pattern - //this->SubShape.setValue(prism); // This crashes with "Illegal storage access". Why? + this->SubShape.setValue(prism); // Cut out the pocket BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), prism); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index a31bebf43..32acdb705 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -48,7 +48,7 @@ using namespace PartDesign; namespace PartDesign { -PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::SketchBased) +PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::Additive) Revolution::Revolution() { @@ -63,7 +63,6 @@ Revolution::Revolution() short Revolution::mustExecute() const { if (Placement.isTouched() || - Sketch.isTouched() || ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || @@ -71,7 +70,7 @@ short Revolution::mustExecute() const Midplane.isTouched() || Reversed.isTouched()) return 1; - return 0; + return Additive::mustExecute(); } App::DocumentObjectExecReturn *Revolution::execute(void) @@ -183,6 +182,8 @@ App::DocumentObjectExecReturn *Revolution::execute(void) if (SupportObject) { const TopoDS_Shape& support = SupportObject->Shape.getValue(); if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) { + // set the additive shape property for later usage in e.g. pattern + this->AddShape.setValue(result); // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); // Let's check if the fusion has been successful diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 19166e2d5..976f473d2 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -25,12 +25,12 @@ #define PARTDESIGN_Revolution_H #include -#include "FeatureSketchBased.h" +#include "FeatureAdditive.h" namespace PartDesign { -class PartDesignExport Revolution : public SketchBased +class PartDesignExport Revolution : public Additive { PROPERTY_HEADER(PartDesign::Revolution); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index ce6323632..3d1bcd092 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -77,6 +77,13 @@ SketchBased::SketchBased() ADD_PROPERTY(Sketch,(0)); } +short SketchBased::mustExecute() const +{ + if (Sketch.isTouched()) + return 1; + return 0; // PartDesign::Feature::mustExecute(); +} + void SketchBased::positionBySketch(void) { Part::Part2DObject *sketch = static_cast(Sketch.getValue()); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 8fab20939..b99d6a15a 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -42,6 +42,8 @@ public: App::PropertyLink Sketch; + short mustExecute() const; + /** calculates and updates the Placement property based on the Sketch * or its support if it has one */ diff --git a/src/Mod/Ship/shipAreasCurve/Plot.py b/src/Mod/Ship/shipAreasCurve/Plot.py index 61b1f3a20..4c2bc46e5 100644 --- a/src/Mod/Ship/shipAreasCurve/Plot.py +++ b/src/Mod/Ship/shipAreasCurve/Plot.py @@ -24,7 +24,8 @@ import os # FreeCAD modules import FreeCAD,FreeCADGui -from FreeCAD import Base, Image, ImageGui +from FreeCAD import Base +import Image, ImageGui # FreeCADShip modules from shipUtils import Paths, Translator diff --git a/src/Mod/Ship/shipHydrostatics/Plot.py b/src/Mod/Ship/shipHydrostatics/Plot.py index 011b45c74..d209bbf59 100644 --- a/src/Mod/Ship/shipHydrostatics/Plot.py +++ b/src/Mod/Ship/shipHydrostatics/Plot.py @@ -26,8 +26,7 @@ import math # FreeCAD modules import FreeCAD,FreeCADGui from FreeCAD import Base, Vector -from FreeCAD import Image, ImageGui -import Part +import Part, Image, ImageGui # FreeCADShip modules from shipUtils import Paths, Translator import Tools diff --git a/src/Mod/Ship/shipHydrostatics/TaskPanel.py b/src/Mod/Ship/shipHydrostatics/TaskPanel.py index 54b5c7623..b5398690e 100644 --- a/src/Mod/Ship/shipHydrostatics/TaskPanel.py +++ b/src/Mod/Ship/shipHydrostatics/TaskPanel.py @@ -1,229 +1,229 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 * -#* * -#*************************************************************************** - -import math -# FreeCAD modules -import FreeCAD as App -import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module -import Plot -import Instance -from shipUtils import Paths, Translator -import Tools - -class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/shipHydrostatics/TaskPanel.ui" - self.ship = None - - def accept(self): - if not self.ship: - return False - self.save() - draft = self.form.minDraft.value() - drafts = [draft] - dDraft = (self.form.maxDraft.value() - self.form.minDraft.value())/(self.form.nDraft.value()-1) - for i in range(1,self.form.nDraft.value()): - draft = draft + dDraft - drafts.append(draft) - Plot.Plot(self.ship, self.form.trim.value(), drafts) - return True - - def reject(self): - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.trim = form.findChild(QtGui.QDoubleSpinBox, "Trim") - form.minDraft = form.findChild(QtGui.QDoubleSpinBox, "MinDraft") - form.maxDraft = form.findChild(QtGui.QDoubleSpinBox, "MaxDraft") - form.nDraft = form.findChild(QtGui.QSpinBox, "NDraft") - self.form = form - # Initial values - if self.initValues(): - return True - self.retranslateUi() - # Connect Signals and Slots - QtCore.QObject.connect(form.trim, QtCore.SIGNAL("valueChanged(double)"), self.onData) - QtCore.QObject.connect(form.minDraft, QtCore.SIGNAL("valueChanged(double)"), self.onData) - QtCore.QObject.connect(form.maxDraft, QtCore.SIGNAL("valueChanged(double)"), self.onData) - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def initValues(self): - """ Set initial values for fields - """ - # Get objects - selObjs = Gui.Selection.getSelection() - if not selObjs: - msg = Translator.translate("Ship instance must be selected (no object selected)\n") - App.Console.PrintError(msg) - return True - for i in range(0,len(selObjs)): - obj = selObjs[i] - # Test if is a ship instance - props = obj.PropertiesList - try: - props.index("IsShip") - except ValueError: - continue - if obj.IsShip: - # Test if another ship already selected - if self.ship: - msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") - App.Console.PrintWarning(msg) - break - self.ship = obj - # Test if any valid ship was selected - if not self.ship: - msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") - App.Console.PrintError(msg) - return True - # Get bounds - bbox = self.ship.Shape.BoundBox - # Set trim - flag = True - try: - props.index("HydrostaticsTrim") - except ValueError: - flag = False - if flag: - self.form.trim.setValue(self.ship.HydrostaticsTrim) - # Set drafts - self.form.maxDraft.setValue(1.1*self.ship.Draft) - self.form.minDraft.setValue(0.9*self.ship.Draft) - # Try to use saved values - props = self.ship.PropertiesList - flag = True - try: - props.index("HydrostaticsMinDraft") - except ValueError: - flag = False - if flag: - self.form.minDraft.setValue(self.ship.HydrostaticsMinDraft) - flag = True - try: - props.index("HydrostaticsMaxDraft") - except ValueError: - flag = False - if flag: - self.form.maxDraft.setValue(self.ship.HydrostaticsMaxDraft) - self.form.maxDraft.setMaximum(bbox.ZMax) - self.form.minDraft.setMinimum(bbox.ZMin) - self.form.maxDraft.setMinimum(self.form.minDraft.value()) - self.form.minDraft.setMaximum(self.form.maxDraft.value()) - flag = True - try: - props.index("HydrostaticsNDraft") - except ValueError: - flag = False - if flag: - self.form.nDraft.setValue(self.ship.HydrostaticsNDraft) - # Update GUI - msg = Translator.translate("Ready to work\n") - App.Console.PrintMessage(msg) - return False - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(Translator.translate("Plot hydrostatics")) - self.form.findChild(QtGui.QLabel, "TrimLabel").setText(Translator.translate("Trim")) - self.form.findChild(QtGui.QLabel, "MinDraftLabel").setText(Translator.translate("Minimum draft")) - self.form.findChild(QtGui.QLabel, "MaxDraftLabel").setText(Translator.translate("Maximum draft")) - self.form.findChild(QtGui.QLabel, "NDraftLabel").setText(Translator.translate("Number of points")) - - def onData(self, value): - """ Method called when input data is changed. - @param value Changed value. - """ - if not self.ship: - return - self.form.maxDraft.setMinimum(self.form.minDraft.value()) - self.form.minDraft.setMaximum(self.form.maxDraft.value()) - - def save(self): - """ Saves data into ship instance. - """ - props = self.ship.PropertiesList - try: - props.index("HydrostaticsTrim") - except ValueError: - self.ship.addProperty("App::PropertyFloat","HydrostaticsTrim","Ship", str(Translator.translate("Hydrostatics trim selected [m]"))) - self.ship.HydrostaticsTrim = self.form.trim.value() - try: - props.index("HydrostaticsMinDraft") - except ValueError: - self.ship.addProperty("App::PropertyFloat","HydrostaticsMinDraft","Ship", str(Translator.translate("Hydrostatics minimum draft selected [m]"))) - self.ship.HydrostaticsMinDraft = self.form.minDraft.value() - try: - props.index("HydrostaticsMaxDraft") - except ValueError: - self.ship.addProperty("App::PropertyFloat","HydrostaticsMaxDraft","Ship", str(Translator.translate("Hydrostatics maximum draft selected [m]"))) - self.ship.HydrostaticsMaxDraft = self.form.maxDraft.value() - try: - props.index("HydrostaticsNDraft") - except ValueError: - self.ship.addProperty("App::PropertyInteger","HydrostaticsNDraft","Ship", str(Translator.translate("Hydrostatics number of points selected [m]"))) - self.ship.HydrostaticsNDraft = self.form.nDraft.value() - -def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +import math +# FreeCAD modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +import Plot +import Instance +from shipUtils import Paths, Translator +import Tools + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/shipHydrostatics/TaskPanel.ui" + self.ship = None + + def accept(self): + if not self.ship: + return False + self.save() + draft = self.form.minDraft.value() + drafts = [draft] + dDraft = (self.form.maxDraft.value() - self.form.minDraft.value())/(self.form.nDraft.value()-1) + for i in range(1,self.form.nDraft.value()): + draft = draft + dDraft + drafts.append(draft) + Plot.Plot(self.ship, self.form.trim.value(), drafts) + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.trim = form.findChild(QtGui.QDoubleSpinBox, "Trim") + form.minDraft = form.findChild(QtGui.QDoubleSpinBox, "MinDraft") + form.maxDraft = form.findChild(QtGui.QDoubleSpinBox, "MaxDraft") + form.nDraft = form.findChild(QtGui.QSpinBox, "NDraft") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + # Connect Signals and Slots + QtCore.QObject.connect(form.trim, QtCore.SIGNAL("valueChanged(double)"), self.onData) + QtCore.QObject.connect(form.minDraft, QtCore.SIGNAL("valueChanged(double)"), self.onData) + QtCore.QObject.connect(form.maxDraft, QtCore.SIGNAL("valueChanged(double)"), self.onData) + + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def initValues(self): + """ Set initial values for fields + """ + # Get objects + selObjs = Gui.Selection.getSelection() + if not selObjs: + msg = Translator.translate("Ship instance must be selected (no object selected)\n") + App.Console.PrintError(msg) + return True + for i in range(0,len(selObjs)): + obj = selObjs[i] + # Test if is a ship instance + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + continue + if obj.IsShip: + # Test if another ship already selected + if self.ship: + msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") + App.Console.PrintWarning(msg) + break + self.ship = obj + # Test if any valid ship was selected + if not self.ship: + msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") + App.Console.PrintError(msg) + return True + # Get bounds + bbox = self.ship.Shape.BoundBox + # Set trim + flag = True + try: + props.index("HydrostaticsTrim") + except ValueError: + flag = False + if flag: + self.form.trim.setValue(self.ship.HydrostaticsTrim) + # Set drafts + self.form.maxDraft.setValue(1.1*self.ship.Draft) + self.form.minDraft.setValue(0.9*self.ship.Draft) + # Try to use saved values + props = self.ship.PropertiesList + flag = True + try: + props.index("HydrostaticsMinDraft") + except ValueError: + flag = False + if flag: + self.form.minDraft.setValue(self.ship.HydrostaticsMinDraft) + flag = True + try: + props.index("HydrostaticsMaxDraft") + except ValueError: + flag = False + if flag: + self.form.maxDraft.setValue(self.ship.HydrostaticsMaxDraft) + self.form.maxDraft.setMaximum(bbox.ZMax) + self.form.minDraft.setMinimum(bbox.ZMin) + self.form.maxDraft.setMinimum(self.form.minDraft.value()) + self.form.minDraft.setMaximum(self.form.maxDraft.value()) + flag = True + try: + props.index("HydrostaticsNDraft") + except ValueError: + flag = False + if flag: + self.form.nDraft.setValue(self.ship.HydrostaticsNDraft) + # Update GUI + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Plot hydrostatics")) + self.form.findChild(QtGui.QLabel, "TrimLabel").setText(Translator.translate("Trim")) + self.form.findChild(QtGui.QLabel, "MinDraftLabel").setText(Translator.translate("Minimum draft")) + self.form.findChild(QtGui.QLabel, "MaxDraftLabel").setText(Translator.translate("Maximum draft")) + self.form.findChild(QtGui.QLabel, "NDraftLabel").setText(Translator.translate("Number of points")) + + def onData(self, value): + """ Method called when input data is changed. + @param value Changed value. + """ + if not self.ship: + return + self.form.maxDraft.setMinimum(self.form.minDraft.value()) + self.form.minDraft.setMaximum(self.form.maxDraft.value()) + + def save(self): + """ Saves data into ship instance. + """ + props = self.ship.PropertiesList + try: + props.index("HydrostaticsTrim") + except ValueError: + self.ship.addProperty("App::PropertyFloat","HydrostaticsTrim","Ship", str(Translator.translate("Hydrostatics trim selected [m]"))) + self.ship.HydrostaticsTrim = self.form.trim.value() + try: + props.index("HydrostaticsMinDraft") + except ValueError: + self.ship.addProperty("App::PropertyFloat","HydrostaticsMinDraft","Ship", str(Translator.translate("Hydrostatics minimum draft selected [m]"))) + self.ship.HydrostaticsMinDraft = self.form.minDraft.value() + try: + props.index("HydrostaticsMaxDraft") + except ValueError: + self.ship.addProperty("App::PropertyFloat","HydrostaticsMaxDraft","Ship", str(Translator.translate("Hydrostatics maximum draft selected [m]"))) + self.ship.HydrostaticsMaxDraft = self.form.maxDraft.value() + try: + props.index("HydrostaticsNDraft") + except ValueError: + self.ship.addProperty("App::PropertyInteger","HydrostaticsNDraft","Ship", str(Translator.translate("Hydrostatics number of points selected [m]"))) + self.ship.HydrostaticsNDraft = self.form.nDraft.value() + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/shipOutlineDraw/Plot.py b/src/Mod/Ship/shipOutlineDraw/Plot.py index 004ab9b40..7715540da 100644 --- a/src/Mod/Ship/shipOutlineDraw/Plot.py +++ b/src/Mod/Ship/shipOutlineDraw/Plot.py @@ -51,7 +51,7 @@ def Plot(scale, sections, shape): x0 = xMid - 0.5*xTot y0 = 297.0 - yMid - 0.5*yTot # 297 = A3_width # Get border - edges = self.getEdges([shape]) + edges = getEdges([shape]) border = edges[0] for i in range(0,len(edges)): border = border.oldFuse(edges[i]) # Only group objects, don't try to build more complex entities @@ -95,7 +95,7 @@ def Plot(scale, sections, shape): FreeCAD.ActiveDocument.recompute() return obj -def getEdges(self, objs=None): +def getEdges(objs=None): """ Returns object edges (list of them) @param objs Object to get the faces, none if selected object may used. diff --git a/src/Mod/Ship/shipOutlineDraw/TaskPanel.py b/src/Mod/Ship/shipOutlineDraw/TaskPanel.py index c49abcd0d..393e11ea8 100644 --- a/src/Mod/Ship/shipOutlineDraw/TaskPanel.py +++ b/src/Mod/Ship/shipOutlineDraw/TaskPanel.py @@ -1,348 +1,348 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2011, 2012 * -#* Jose Luis Cercos Pita * -#* * -#* 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 * -#* * -#*************************************************************************** - -# FreeCAD modules -import FreeCAD as App -import FreeCADGui as Gui -# Qt library -from PyQt4 import QtGui,QtCore -# Module -import Preview, Plot -import Instance -from shipUtils import Paths, Translator - -class TaskPanel: - def __init__(self): - self.ui = Paths.modulePath() + "/shipOutlineDraw/TaskPanel.ui" - self.ship = None - self.skip = False - self.LSections = [] - self.BSections = [] - self.TSections = [] - self.obj = None - self.preview = Preview.Preview() - - def accept(self): - self.saveSections() - self.obj = Plot.Plot(self.form.scale.value(), self.obj.Shape, self.ship.Shape) - self.preview.clean() - self.obj.Label = 'OutlineDraw' - return True - - def reject(self): - self.preview.clean() - return True - - def clicked(self, index): - pass - - def open(self): - pass - - def needsFullSpace(self): - return True - - def isAllowedAlterSelection(self): - return False - - def isAllowedAlterView(self): - return True - - def isAllowedAlterDocument(self): - return False - - def helpRequested(self): - pass - - def setupUi(self): - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.sections = form.findChild(QtGui.QTableWidget, "Sections") - try: - form.sections.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly) - except: - msg = Translator.translate("QtCore.Qt.ImhFormattedNumbersOnly not supported, will not used.\n") - App.Console.PrintWarning(msg) - form.sectionType = form.findChild(QtGui.QComboBox, "SectionType") - form.deleteButton = form.findChild(QtGui.QPushButton, "DeleteButton") - form.nSections = form.findChild(QtGui.QSpinBox, "NSections") - form.createButton = form.findChild(QtGui.QPushButton, "CreateButton") - form.scale = form.findChild(QtGui.QSpinBox, "Scale") - self.form = form - # Initial values - if self.initValues(): - return True - self.retranslateUi() - self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) - # Connect Signals and Slots - QtCore.QObject.connect(form.sectionType,QtCore.SIGNAL("activated(QString)"),self.onSectionType) - QtCore.QObject.connect(form.sections,QtCore.SIGNAL("cellChanged(int,int)"),self.onTableItem); - QtCore.QObject.connect(form.deleteButton,QtCore.SIGNAL("pressed()"),self.onDeleteButton) - QtCore.QObject.connect(form.createButton,QtCore.SIGNAL("pressed()"),self.onCreateButton) - - def getMainWindow(self): - "returns the main window" - # using QtGui.qApp.activeWindow() isn't very reliable because if another - # widget than the mainwindow is active (e.g. a dialog) the wrong widget is - # returned - toplevel = QtGui.qApp.topLevelWidgets() - for i in toplevel: - if i.metaObject().className() == "Gui::MainWindow": - return i - raise Exception("No main window found") - - def initValues(self): - """ Set initial values for fields - """ - # Get selected objects - selObjs = Gui.Selection.getSelection() - if not selObjs: - msg = Translator.translate("Ship instance must be selected (no object selected)\n") - App.Console.PrintError(msg) - return True - for i in range(0,len(selObjs)): - obj = selObjs[i] - # Test if is a ship instance - props = obj.PropertiesList - try: - props.index("IsShip") - except ValueError: - continue - if obj.IsShip: - # Test if another ship already selected - if self.ship: - msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") - App.Console.PrintWarning(msg) - break - self.ship = obj - # Test if any valid ship was selected - if not self.ship: - msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") - App.Console.PrintError(msg) - return True - # Load sections (if exist) - self.loadSections() - msg = Translator.translate("Ready to work\n") - App.Console.PrintMessage(msg) - return False - - def retranslateUi(self): - """ Set user interface locale strings. - """ - self.form.setWindowTitle(Translator.translate("Outline draw")) - self.form.findChild(QtGui.QGroupBox, "AutoCreateBox").setTitle(Translator.translate("Auto create")) - self.form.findChild(QtGui.QGroupBox, "ScaleBox").setTitle(Translator.translate("Scale")) - self.form.findChild(QtGui.QPushButton, "DeleteButton").setText(Translator.translate("Delete all sections")) - self.form.findChild(QtGui.QPushButton, "CreateButton").setText(Translator.translate("Create sections")) - self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(0, Translator.translate("Transversal")) - self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(1, Translator.translate("Longitudinal")) - self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(2, Translator.translate("Water lines")) - - def onSectionType(self): - """ Function called when the section type is changed. - """ - # Search section type - ID = self.form.sectionType.currentIndex() - self.setSectionType(ID) - - def setSectionType(self, ID): - """ Function that set the type section related table. - @param ID Id of the section to set: \n - 0 = Transversal sections \n - 1 = Longitudinal sections \n - 2 = Water lines - """ - SectionList = [] - if ID == 0: - SectionList = self.LSections[:] - elif ID == 1: - SectionList = self.BSections[:] - elif ID == 2: - SectionList = self.TSections[:] - nRow = len(SectionList) - self.form.sections.clearContents() - self.form.sections.setRowCount(nRow+1) - if not nRow: - self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) - return - self.skip = True # Avoid recursive call to OnItem - for i in range(0,nRow): - if i == nRow-1: - self.skip = False - string = '%f' % (SectionList[i]) - item = QtGui.QTableWidgetItem(string) - self.form.sections.setItem(i,0,item) - - def onTableItem(self, row, column): - """ Function called when an item of table is changed. - @param row Changed item row - @param column Changed item column - """ - if self.skip: - return - # Ensure that exist one empty item at least - nRow = self.form.sections.rowCount() - item = self.form.sections.item(nRow-1,0) - if item : - if(item.text() != ''): - self.form.sections.setRowCount(nRow+1) - # Ensure that new item is a number - ID = self.form.sectionType.currentIndex() - if ID == 0: - SectionList = self.LSections[:] - elif ID == 1: - SectionList = self.BSections[:] - elif ID == 2: - SectionList = self.TSections[:] - item = self.form.sections.item(row,column) - (number,flag) = item.text().toFloat() - if not flag: - if len(SectionList) > nRow-1: - number = SectionList[nRow-1] - else: - number = 0.0 - string = '%f' % (number) - item.setText(string) - # Regenerate the list - SectionList = [] - for i in range(0,nRow): - item = self.form.sections.item(i,0) - if item: - (number,flag) = item.text().toFloat() - SectionList.append(number) - # Paste it into the class list - ID = self.form.sectionType.currentIndex() - if ID == 0: - self.LSections = SectionList[:] - elif ID == 1: - self.BSections = SectionList[:] - elif ID == 2: - self.TSections = SectionList[:] - self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) - - def onDeleteButton(self): - """ Function called when the delete button is pressed. - All sections mustt be erased - """ - self.form.sections.clearContents() - self.form.sections.setRowCount(1) - # Clear active list - ID = self.form.sectionType.currentIndex() - if ID == 0: - self.LSections = [] - elif ID == 1: - self.BSections = [] - elif ID == 2: - self.TSections = [] - self.setSectionType(ID) - - def onCreateButton(self): - """ Function called when create button is pressed. - Several sections must be added to list - """ - # Recolect data - nSections = self.form.nSections.value() - SectionList = [] - L = 0.0 - ID = self.form.sectionType.currentIndex() - if ID == 0: - L = self.ship.Length - d = L / (nSections-1) # Distance between sections - start = - L/2.0 # Ship must have 0.0 at coordinates origin - elif ID == 1: - L = -0.5*self.ship.Beam # Ship must be in y<0.0 - d = L / (nSections+1.0) # Distance between sections - start = d - elif ID == 2: - L = self.ship.Draft - d = L / (nSections) # Distance between sections - start = d - # Calculate sections - for i in range(0,nSections): - sec = i*d + start - SectionList.append(sec) - # Paste into class table - if ID == 0: - self.LSections = SectionList[:] - elif ID == 1: - self.BSections = SectionList[:] - elif ID == 2: - self.TSections = SectionList[:] - # Print the table - self.setSectionType(ID) - - def loadSections(self): - """ Loads from ship object previously selected sections. - """ - # Load sections - props = self.ship.PropertiesList - flag=True - try: - props.index("LSections") - except ValueError: - flag=False - if flag: - self.LSections = self.ship.LSections[:] - self.BSections = self.ship.BSections[:] - self.TSections = self.ship.TSections[:] - # Load scale too - flag=True - try: - props.index("PlotScale") - except ValueError: - flag=False - if flag: - self.form.scale.setValue(self.ship.PlotScale) - # Set UI - self.setSectionType(self.form.sectionType.currentIndex()) - - def saveSections(self): - """ Save selected sections into ship object. - """ - # Test if previous section have been created - props = self.ship.PropertiesList - try: - props.index("LSections") - except ValueError: - # Create new sections list - self.ship.addProperty("App::PropertyFloatList","LSections","Ship", str(Translator.translate("Transversal sections position [m]"))).LSections=[] - self.ship.addProperty("App::PropertyFloatList","BSections","Ship", str(Translator.translate("Longitudinal sections position [m]"))).BSections=[] - self.ship.addProperty("App::PropertyFloatList","TSections","Ship", str(Translator.translate("Water lines position [m]"))).TSections=[] - # Save sections - self.ship.LSections = self.LSections[:] - self.ship.BSections = self.BSections[:] - self.ship.TSections = self.TSections[:] - # Save also scale - try: - props.index("PlotScale") - except ValueError: - self.ship.addProperty("App::PropertyInteger","PlotScale","Ship", str(Translator.translate("Plot scale (1:scale format)"))).PlotScale=250 - self.ship.PlotScale = self.form.scale.value() - -def createTask(): - panel = TaskPanel() - Gui.Control.showDialog(panel) - if panel.setupUi(): - Gui.Control.closeDialog(panel) - return None - return panel +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +import Preview, Plot +import Instance +from shipUtils import Paths, Translator + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/shipOutlineDraw/TaskPanel.ui" + self.ship = None + self.skip = False + self.LSections = [] + self.BSections = [] + self.TSections = [] + self.obj = None + self.preview = Preview.Preview() + + def accept(self): + self.saveSections() + self.obj = Plot.Plot(self.form.scale.value(), self.obj.Shape, self.ship.Shape) + self.preview.clean() + self.obj.Label = 'OutlineDraw' + return True + + def reject(self): + self.preview.clean() + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.sections = form.findChild(QtGui.QTableWidget, "Sections") + try: + form.sections.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly) + except: + msg = Translator.translate("QtCore.Qt.ImhFormattedNumbersOnly not supported, will not used.\n") + App.Console.PrintWarning(msg) + form.sectionType = form.findChild(QtGui.QComboBox, "SectionType") + form.deleteButton = form.findChild(QtGui.QPushButton, "DeleteButton") + form.nSections = form.findChild(QtGui.QSpinBox, "NSections") + form.createButton = form.findChild(QtGui.QPushButton, "CreateButton") + form.scale = form.findChild(QtGui.QSpinBox, "Scale") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) + # Connect Signals and Slots + QtCore.QObject.connect(form.sectionType,QtCore.SIGNAL("activated(QString)"),self.onSectionType) + QtCore.QObject.connect(form.sections,QtCore.SIGNAL("cellChanged(int,int)"),self.onTableItem); + QtCore.QObject.connect(form.deleteButton,QtCore.SIGNAL("pressed()"),self.onDeleteButton) + QtCore.QObject.connect(form.createButton,QtCore.SIGNAL("pressed()"),self.onCreateButton) + + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def initValues(self): + """ Set initial values for fields + """ + # Get selected objects + selObjs = Gui.Selection.getSelection() + if not selObjs: + msg = Translator.translate("Ship instance must be selected (no object selected)\n") + App.Console.PrintError(msg) + return True + for i in range(0,len(selObjs)): + obj = selObjs[i] + # Test if is a ship instance + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + continue + if obj.IsShip: + # Test if another ship already selected + if self.ship: + msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") + App.Console.PrintWarning(msg) + break + self.ship = obj + # Test if any valid ship was selected + if not self.ship: + msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") + App.Console.PrintError(msg) + return True + # Load sections (if exist) + self.loadSections() + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Outline draw")) + self.form.findChild(QtGui.QGroupBox, "AutoCreateBox").setTitle(Translator.translate("Auto create")) + self.form.findChild(QtGui.QGroupBox, "ScaleBox").setTitle(Translator.translate("Scale")) + self.form.findChild(QtGui.QPushButton, "DeleteButton").setText(Translator.translate("Delete all sections")) + self.form.findChild(QtGui.QPushButton, "CreateButton").setText(Translator.translate("Create sections")) + self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(0, Translator.translate("Transversal")) + self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(1, Translator.translate("Longitudinal")) + self.form.findChild(QtGui.QComboBox, "SectionType").setItemText(2, Translator.translate("Water lines")) + + def onSectionType(self): + """ Function called when the section type is changed. + """ + # Search section type + ID = self.form.sectionType.currentIndex() + self.setSectionType(ID) + + def setSectionType(self, ID): + """ Function that set the type section related table. + @param ID Id of the section to set: \n + 0 = Transversal sections \n + 1 = Longitudinal sections \n + 2 = Water lines + """ + SectionList = [] + if ID == 0: + SectionList = self.LSections[:] + elif ID == 1: + SectionList = self.BSections[:] + elif ID == 2: + SectionList = self.TSections[:] + nRow = len(SectionList) + self.form.sections.clearContents() + self.form.sections.setRowCount(nRow+1) + if not nRow: + self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) + return + self.skip = True # Avoid recursive call to OnItem + for i in range(0,nRow): + if i == nRow-1: + self.skip = False + string = '%f' % (SectionList[i]) + item = QtGui.QTableWidgetItem(string) + self.form.sections.setItem(i,0,item) + + def onTableItem(self, row, column): + """ Function called when an item of table is changed. + @param row Changed item row + @param column Changed item column + """ + if self.skip: + return + # Ensure that exist one empty item at least + nRow = self.form.sections.rowCount() + item = self.form.sections.item(nRow-1,0) + if item : + if(item.text() != ''): + self.form.sections.setRowCount(nRow+1) + # Ensure that new item is a number + ID = self.form.sectionType.currentIndex() + if ID == 0: + SectionList = self.LSections[:] + elif ID == 1: + SectionList = self.BSections[:] + elif ID == 2: + SectionList = self.TSections[:] + item = self.form.sections.item(row,column) + (number,flag) = item.text().toFloat() + if not flag: + if len(SectionList) > nRow-1: + number = SectionList[nRow-1] + else: + number = 0.0 + string = '%f' % (number) + item.setText(string) + # Regenerate the list + SectionList = [] + for i in range(0,nRow): + item = self.form.sections.item(i,0) + if item: + (number,flag) = item.text().toFloat() + SectionList.append(number) + # Paste it into the class list + ID = self.form.sectionType.currentIndex() + if ID == 0: + self.LSections = SectionList[:] + elif ID == 1: + self.BSections = SectionList[:] + elif ID == 2: + self.TSections = SectionList[:] + self.obj = self.preview.update(self.ship.Length, self.ship.Beam, self.ship.Draft, self.LSections,self.BSections,self.TSections, self.ship.Shape) + + def onDeleteButton(self): + """ Function called when the delete button is pressed. + All sections mustt be erased + """ + self.form.sections.clearContents() + self.form.sections.setRowCount(1) + # Clear active list + ID = self.form.sectionType.currentIndex() + if ID == 0: + self.LSections = [] + elif ID == 1: + self.BSections = [] + elif ID == 2: + self.TSections = [] + self.setSectionType(ID) + + def onCreateButton(self): + """ Function called when create button is pressed. + Several sections must be added to list + """ + # Recolect data + nSections = self.form.nSections.value() + SectionList = [] + L = 0.0 + ID = self.form.sectionType.currentIndex() + if ID == 0: + L = self.ship.Length + d = L / (nSections-1) # Distance between sections + start = - L/2.0 # Ship must have 0.0 at coordinates origin + elif ID == 1: + L = -0.5*self.ship.Beam # Ship must be in y<0.0 + d = L / (nSections+1.0) # Distance between sections + start = d + elif ID == 2: + L = self.ship.Draft + d = L / (nSections) # Distance between sections + start = d + # Calculate sections + for i in range(0,nSections): + sec = i*d + start + SectionList.append(sec) + # Paste into class table + if ID == 0: + self.LSections = SectionList[:] + elif ID == 1: + self.BSections = SectionList[:] + elif ID == 2: + self.TSections = SectionList[:] + # Print the table + self.setSectionType(ID) + + def loadSections(self): + """ Loads from ship object previously selected sections. + """ + # Load sections + props = self.ship.PropertiesList + flag=True + try: + props.index("LSections") + except ValueError: + flag=False + if flag: + self.LSections = self.ship.LSections[:] + self.BSections = self.ship.BSections[:] + self.TSections = self.ship.TSections[:] + # Load scale too + flag=True + try: + props.index("PlotScale") + except ValueError: + flag=False + if flag: + self.form.scale.setValue(self.ship.PlotScale) + # Set UI + self.setSectionType(self.form.sectionType.currentIndex()) + + def saveSections(self): + """ Save selected sections into ship object. + """ + # Test if previous section have been created + props = self.ship.PropertiesList + try: + props.index("LSections") + except ValueError: + # Create new sections list + self.ship.addProperty("App::PropertyFloatList","LSections","Ship", str(Translator.translate("Transversal sections position [m]"))).LSections=[] + self.ship.addProperty("App::PropertyFloatList","BSections","Ship", str(Translator.translate("Longitudinal sections position [m]"))).BSections=[] + self.ship.addProperty("App::PropertyFloatList","TSections","Ship", str(Translator.translate("Water lines position [m]"))).TSections=[] + # Save sections + self.ship.LSections = self.LSections[:] + self.ship.BSections = self.BSections[:] + self.ship.TSections = self.TSections[:] + # Save also scale + try: + props.index("PlotScale") + except ValueError: + self.ship.addProperty("App::PropertyInteger","PlotScale","Ship", str(Translator.translate("Plot scale (1:scale format)"))).PlotScale=250 + self.ship.PlotScale = self.form.scale.value() + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/tankGZ/Plot.py b/src/Mod/Ship/tankGZ/Plot.py index 09db5345b..320f20185 100644 --- a/src/Mod/Ship/tankGZ/Plot.py +++ b/src/Mod/Ship/tankGZ/Plot.py @@ -24,8 +24,8 @@ import os # FreeCAD modules import FreeCAD,FreeCADGui -from FreeCAD import Base, Image, ImageGui -import Part +from FreeCAD import Base +import Part, Image, ImageGui # FreeCADShip modules from shipUtils import Paths, Translator