Merge branch 'refs/heads/master' into jriegel/develop-fem
This commit is contained in:
commit
9d05dcc85c
|
@ -212,26 +212,60 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
|
||||||
if(NOT DEFINED OCE_DIR)
|
if(NOT DEFINED OCE_DIR)
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
set(OCE_DIR "/usr/local/share/cmake/")
|
set(OCE_DIR "/usr/local/share/cmake/")
|
||||||
else()
|
elseif(WIN32)
|
||||||
set(OCE_DIR "c:/OCE-0.4.0/share/cmake")
|
set(OCE_DIR "c:/OCE-0.4.0/share/cmake")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
find_package ( OCE )
|
find_package (OCE QUIET)
|
||||||
if(${OCE_FOUND})
|
if(${OCE_FOUND})
|
||||||
message("-- OpenCASCADE Community Edition has been found.")
|
message("-- OpenCASCADE Community Edition has been found.")
|
||||||
add_definitions (-DHAVE_CONFIG_H)
|
add_definitions (-DHAVE_CONFIG_H)
|
||||||
set( OCC_LIBRARIES "TKFeat;TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake
|
#lib list copied from FreeCAD's FindOpenCasCade.cmake
|
||||||
set( OCC_OCAF_LIBRARIES "TKCAF;TKXCAF;TKLCAF;TKXDESTEP;TKXDEIGES;TKMeshVS;TKAdvTools" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake
|
set(OCC_LIBRARIES
|
||||||
|
TKFillet
|
||||||
|
TKMesh
|
||||||
|
TKernel
|
||||||
|
TKG2d
|
||||||
|
TKG3d
|
||||||
|
TKMath
|
||||||
|
TKIGES
|
||||||
|
TKSTL
|
||||||
|
TKShHealing
|
||||||
|
TKXSBase
|
||||||
|
TKBool
|
||||||
|
TKBO
|
||||||
|
TKBRep
|
||||||
|
TKTopAlgo
|
||||||
|
TKGeomAlgo
|
||||||
|
TKGeomBase
|
||||||
|
TKOffset
|
||||||
|
TKPrim
|
||||||
|
TKSTEP
|
||||||
|
TKSTEPBase
|
||||||
|
TKSTEPAttr
|
||||||
|
TKHLR
|
||||||
|
TKFeat
|
||||||
|
)
|
||||||
|
#lib list copied from FreeCAD's FindOpenCasCade.cmake
|
||||||
|
set(OCC_OCAF_LIBRARIES
|
||||||
|
TKCAF
|
||||||
|
TKXCAF
|
||||||
|
TKLCAF
|
||||||
|
TKXDESTEP
|
||||||
|
TKXDEIGES
|
||||||
|
TKMeshVS
|
||||||
|
TKAdvTools
|
||||||
|
)
|
||||||
set(OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS})
|
set(OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS})
|
||||||
set(OCC_FOUND ${OCE_FOUND})
|
set(OCC_FOUND ${OCE_FOUND})
|
||||||
else() #look for OpenCASCADE
|
else() #look for OpenCASCADE
|
||||||
find_package(OpenCasCade)
|
find_package(OpenCasCade)
|
||||||
IF(NOT OCC_FOUND)
|
if(NOT OCC_FOUND)
|
||||||
MESSAGE("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
|
message("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
|
||||||
ELSE()
|
else()
|
||||||
MESSAGE("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}")
|
message("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}")
|
||||||
MESSAGE("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}")
|
message("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}")
|
||||||
ENDIF()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# -------------------------------- Salome SMESH --------------------------
|
# -------------------------------- Salome SMESH --------------------------
|
||||||
|
@ -362,6 +396,17 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
|
||||||
find_package(Spnav)
|
find_package(Spnav)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
|
# -------------------------------- Shiboken/PySide ------------------------
|
||||||
|
|
||||||
|
find_package(Shiboken QUIET)
|
||||||
|
IF(SHIBOKEN_INCLUDE_DIR)
|
||||||
|
message("-- Shiboken has been found.")
|
||||||
|
ENDIF(SHIBOKEN_INCLUDE_DIR)
|
||||||
|
find_package(PySide QUIET)
|
||||||
|
IF(PYSIDE_INCLUDE_DIR)
|
||||||
|
message("-- PySide has been found.")
|
||||||
|
ENDIF(PYSIDE_INCLUDE_DIR)
|
||||||
|
|
||||||
# ------------------------------ Matplotlib ------------------------------
|
# ------------------------------ Matplotlib ------------------------------
|
||||||
|
|
||||||
find_package(Matplotlib)
|
find_package(Matplotlib)
|
||||||
|
@ -441,8 +486,14 @@ IF(APPLE)
|
||||||
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
||||||
ENDIF(APPLE)
|
ENDIF(APPLE)
|
||||||
|
|
||||||
|
# force build directory to be different to source directory
|
||||||
|
#if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||||
|
#MESSAGE(SEND_ERROR "The build directory (${CMAKE_BINARY_DIR}) must be different to the source directory "
|
||||||
|
# "(${CMAKE_SOURCE_DIR}). Please choose another build directory!")
|
||||||
|
#elseif()
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(data)
|
add_subdirectory(data)
|
||||||
|
#endif()
|
||||||
|
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
# == Packaging ===================================================================
|
# == Packaging ===================================================================
|
||||||
|
|
|
@ -83,3 +83,7 @@ because it contains some Fortran code.
|
||||||
project.
|
project.
|
||||||
9. Build the file vcf2c.lib with "nmake -f makefile.vc" and add it to the MEFISTO2 project as
|
9. Build the file vcf2c.lib with "nmake -f makefile.vc" and add it to the MEFISTO2 project as
|
||||||
additional library. The linker errors should now go away.
|
additional library. The linker errors should now go away.
|
||||||
|
|
||||||
|
* FreeType
|
||||||
|
|
||||||
|
http://stackoverflow.com/questions/6207176/compiling-freetype-to-dll-as-opposed-to-static-library
|
||||||
|
|
|
@ -13,6 +13,7 @@ IF (WIN32)
|
||||||
FIND_PATH(COIN3D_INCLUDE_DIR Inventor/So.h
|
FIND_PATH(COIN3D_INCLUDE_DIR Inventor/So.h
|
||||||
/usr/include
|
/usr/include
|
||||||
/usr/local/include
|
/usr/local/include
|
||||||
|
/usr/include/coin
|
||||||
)
|
)
|
||||||
|
|
||||||
FIND_LIBRARY(COIN3D_LIBRARY Coin
|
FIND_LIBRARY(COIN3D_LIBRARY Coin
|
||||||
|
|
|
@ -196,6 +196,8 @@ include(AddFileDependencies)
|
||||||
|
|
||||||
macro(fc_wrap_cpp outfiles )
|
macro(fc_wrap_cpp outfiles )
|
||||||
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
||||||
|
# fixes bug 0000585: bug with boost 1.48
|
||||||
|
SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
|
||||||
SET(ARGN)
|
SET(ARGN)
|
||||||
foreach(it ${moc_files})
|
foreach(it ${moc_files})
|
||||||
get_filename_component(it ${it} ABSOLUTE)
|
get_filename_component(it ${it} ABSOLUTE)
|
||||||
|
|
|
@ -207,6 +207,8 @@ include(AddFileDependencies)
|
||||||
|
|
||||||
macro(fc_wrap_cpp outfiles )
|
macro(fc_wrap_cpp outfiles )
|
||||||
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
||||||
|
# fixes bug 0000585: bug with boost 1.48
|
||||||
|
SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
|
||||||
SET(ARGN)
|
SET(ARGN)
|
||||||
foreach(it ${moc_files})
|
foreach(it ${moc_files})
|
||||||
get_filename_component(it ${it} ABSOLUTE)
|
get_filename_component(it ${it} ABSOLUTE)
|
||||||
|
|
|
@ -219,6 +219,8 @@ include(AddFileDependencies)
|
||||||
|
|
||||||
macro(fc_wrap_cpp outfiles )
|
macro(fc_wrap_cpp outfiles )
|
||||||
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
||||||
|
# fixes bug 0000585: bug with boost 1.48
|
||||||
|
SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
|
||||||
SET(ARGN)
|
SET(ARGN)
|
||||||
foreach(it ${moc_files})
|
foreach(it ${moc_files})
|
||||||
get_filename_component(it ${it} ABSOLUTE)
|
get_filename_component(it ${it} ABSOLUTE)
|
||||||
|
@ -392,5 +394,19 @@ SET(EIGEN3_INCLUDE_DIR ${FREECAD_LIBPACK_DIR}/include/eigen3)
|
||||||
set(EIGEN3_FOUND TRUE)
|
set(EIGEN3_FOUND TRUE)
|
||||||
|
|
||||||
|
|
||||||
|
# FreeType
|
||||||
|
if(FREECAD_USE_FREETYPE)
|
||||||
|
set(FREETYPE_LIBRARIES
|
||||||
|
optimized ${FREECAD_LIBPACK_DIR}/lib/freetype.lib
|
||||||
|
debug ${FREECAD_LIBPACK_DIR}/lib/freetyped.lib
|
||||||
|
)
|
||||||
|
set(FREETYPE_INCLUDE_DIRS
|
||||||
|
${FREECAD_LIBPACK_DIR}/include/FreeType-2.4.12
|
||||||
|
)
|
||||||
|
set(FREETYPE_VERSION_STRING
|
||||||
|
"2.4.12"
|
||||||
|
)
|
||||||
|
set(FREETYPE_FOUND
|
||||||
|
TRUE
|
||||||
|
)
|
||||||
|
endif(FREECAD_USE_FREETYPE)
|
||||||
|
|
|
@ -230,6 +230,8 @@ include(AddFileDependencies)
|
||||||
|
|
||||||
macro(fc_wrap_cpp outfiles )
|
macro(fc_wrap_cpp outfiles )
|
||||||
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN})
|
||||||
|
# fixes bug 0000585: bug with boost 1.48
|
||||||
|
SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
|
||||||
SET(ARGN)
|
SET(ARGN)
|
||||||
foreach(it ${moc_files})
|
foreach(it ${moc_files})
|
||||||
get_filename_component(it ${it} ABSOLUTE)
|
get_filename_component(it ${it} ABSOLUTE)
|
||||||
|
@ -400,5 +402,19 @@ set(ODE_INCLUDE_DIRS ${FREECAD_LIBPACK_DIR}/include/ode-0.11.1)
|
||||||
set(ODE_LIBRARIES ${FREECAD_LIBPACK_DIR}/lib/ode_double.lib)
|
set(ODE_LIBRARIES ${FREECAD_LIBPACK_DIR}/lib/ode_double.lib)
|
||||||
set(ODE_FOUND TRUE)
|
set(ODE_FOUND TRUE)
|
||||||
|
|
||||||
|
# FreeType
|
||||||
|
if(FREECAD_USE_FREETYPE)
|
||||||
|
set(FREETYPE_LIBRARIES
|
||||||
|
optimized ${FREECAD_LIBPACK_DIR}/lib/freetype.lib
|
||||||
|
debug ${FREECAD_LIBPACK_DIR}/lib/freetyped.lib
|
||||||
|
)
|
||||||
|
set(FREETYPE_INCLUDE_DIRS
|
||||||
|
${FREECAD_LIBPACK_DIR}/include/FreeType-2.4.12
|
||||||
|
)
|
||||||
|
set(FREETYPE_VERSION_STRING
|
||||||
|
"2.4.12"
|
||||||
|
)
|
||||||
|
set(FREETYPE_FOUND
|
||||||
|
TRUE
|
||||||
|
)
|
||||||
|
endif(FREECAD_USE_FREETYPE)
|
||||||
|
|
|
@ -12,7 +12,10 @@ ADD_CUSTOM_TARGET(Example_data ALL
|
||||||
SOURCES ${Examples_Files}
|
SOURCES ${Examples_Files}
|
||||||
)
|
)
|
||||||
|
|
||||||
fc_copy_sources(Examples "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files})
|
# 0001097: CMake stops with error "Circular ... <- ... dependency dropped."
|
||||||
|
if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||||
|
fc_copy_sources(Example_data "${CMAKE_BINARY_DIR}/data/examples" ${Examples_Files})
|
||||||
|
endif()
|
||||||
|
|
||||||
INSTALL(
|
INSTALL(
|
||||||
FILES
|
FILES
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
freecad (0.13-1precise2) precise; urgency=low
|
||||||
|
|
||||||
|
* Fix hard dependency on libgl1-mesa-glx preventing installation on
|
||||||
|
Ubuntu 12.04.2 with LTSEnablementStack. Removal of shlibs.local file
|
||||||
|
and libgl1-mesa-dev deleted from BuildDeps.
|
||||||
|
* Removed version number from libsoqt4-dev BD.
|
||||||
|
|
||||||
|
-- Normand Chamberland <gemnoc@gmail.com> Sun, 05 May 2013 18:31:47 -0400
|
||||||
|
|
||||||
|
freecad (0.13-1precise1) precise; urgency=low
|
||||||
|
|
||||||
|
* New release for Ubuntu 12.04 (precise)
|
||||||
|
|
||||||
|
-- Normand Chamberland <gemnoc@gmail.com> Sun, 06 May 2012 14:38:12 -0400
|
||||||
|
|
||||||
freecad (0.11.3729.dfsg-2) unstable; urgency=low
|
freecad (0.11.3729.dfsg-2) unstable; urgency=low
|
||||||
|
|
||||||
* Add gfortran and libopencascade-visualization-dev to BD
|
* Add gfortran and libopencascade-visualization-dev to BD
|
||||||
|
@ -29,6 +44,25 @@ freecad (0.11.3729.dfsg-1) unstable; urgency=low
|
||||||
|
|
||||||
-- "Adam C. Powell, IV" <hazelsct@debian.org> Tue, 12 Apr 2011 23:40:30 -0400
|
-- "Adam C. Powell, IV" <hazelsct@debian.org> Tue, 12 Apr 2011 23:40:30 -0400
|
||||||
|
|
||||||
|
freecad (0.10.3247.dfsg-2ubuntu3) natty; urgency=low
|
||||||
|
|
||||||
|
* Fix build failure with ld --as-needed.
|
||||||
|
|
||||||
|
-- Matthias Klose <doko@ubuntu.com> Wed, 15 Dec 2010 01:12:39 +0100
|
||||||
|
|
||||||
|
freecad (0.10.3247.dfsg-2ubuntu2) natty; urgency=low
|
||||||
|
|
||||||
|
* Rebuild with python 2.7 as the python default.
|
||||||
|
|
||||||
|
-- Matthias Klose <doko@ubuntu.com> Thu, 09 Dec 2010 16:46:45 +0000
|
||||||
|
|
||||||
|
freecad (0.10.3247.dfsg-2ubuntu1) natty; urgency=low
|
||||||
|
|
||||||
|
* Merge from debian unstable. Remaining changes:
|
||||||
|
- build on libqtwebkit-dev for qtwebkit transition
|
||||||
|
|
||||||
|
-- Bhavani Shankar <bhavi@ubuntu.com> Wed, 20 Oct 2010 08:40:53 +0530
|
||||||
|
|
||||||
freecad (0.10.3247.dfsg-2) unstable; urgency=low
|
freecad (0.10.3247.dfsg-2) unstable; urgency=low
|
||||||
|
|
||||||
* control:
|
* control:
|
||||||
|
@ -43,6 +77,20 @@ freecad (0.10.3247.dfsg-2) unstable; urgency=low
|
||||||
|
|
||||||
-- Teemu Ikonen <tpikonen@gmail.com> Wed, 18 Aug 2010 19:34:36 +0200
|
-- Teemu Ikonen <tpikonen@gmail.com> Wed, 18 Aug 2010 19:34:36 +0200
|
||||||
|
|
||||||
|
freecad (0.10.3247.dfsg-1ubuntu2) maverick; urgency=low
|
||||||
|
|
||||||
|
* Rebuild on libqtwebkit-dev for qtwebkit transition
|
||||||
|
|
||||||
|
-- Jonathan Riddell <jriddell@ubuntu.com> Wed, 21 Jul 2010 10:06:31 +0100
|
||||||
|
|
||||||
|
freecad (0.10.3247.dfsg-1ubuntu1) maverick; urgency=low
|
||||||
|
|
||||||
|
* Merge from Debian unstable, remaining changes:
|
||||||
|
- debian/control: Build-Depends on libqt4-webkit-dev due to
|
||||||
|
QtWebKit is no longer part of libqt4-dev (LP: #604078)
|
||||||
|
|
||||||
|
-- Artur Rona <ari-tczew@tlen.pl> Sat, 10 Jul 2010 21:06:47 +0200
|
||||||
|
|
||||||
freecad (0.10.3247.dfsg-1) unstable; urgency=low
|
freecad (0.10.3247.dfsg-1) unstable; urgency=low
|
||||||
|
|
||||||
* New upstream version (closes: #582627)
|
* New upstream version (closes: #582627)
|
||||||
|
@ -57,6 +105,12 @@ freecad (0.10.3247.dfsg-1) unstable; urgency=low
|
||||||
|
|
||||||
-- Teemu Ikonen <tpikonen@gmail.com> Mon, 05 Jul 2010 15:07:49 +0200
|
-- Teemu Ikonen <tpikonen@gmail.com> Mon, 05 Jul 2010 15:07:49 +0200
|
||||||
|
|
||||||
|
freecad (0.9.2646.5.dfsg-1ubuntu1) maverick; urgency=low
|
||||||
|
|
||||||
|
* Add build-dep on libqt4-webkit-dev to fix FTBFS with Qt 4.7
|
||||||
|
|
||||||
|
-- Scott Kitterman <scott@kitterman.com> Sat, 19 Jun 2010 00:37:12 -0400
|
||||||
|
|
||||||
freecad (0.9.2646.5.dfsg-1) unstable; urgency=low
|
freecad (0.9.2646.5.dfsg-1) unstable; urgency=low
|
||||||
|
|
||||||
* Add 'dfsg' extension to upstream version, upstream sources are unchanged.
|
* Add 'dfsg' extension to upstream version, upstream sources are unchanged.
|
||||||
|
|
|
@ -5,25 +5,26 @@ Maintainer: Debian Science Maintainers <debian-science-maintainers@lists.alioth.
|
||||||
Uploaders: Teemu Ikonen <tpikonen@gmail.com>, "Adam C. Powell, IV" <hazelsct@debian.org>, Anton Gladky <gladky.anton@gmail.com>
|
Uploaders: Teemu Ikonen <tpikonen@gmail.com>, "Adam C. Powell, IV" <hazelsct@debian.org>, Anton Gladky <gladky.anton@gmail.com>
|
||||||
Vcs-Browser: http://git.debian.org/?p=debian-science/packages/freecad.git
|
Vcs-Browser: http://git.debian.org/?p=debian-science/packages/freecad.git
|
||||||
Vcs-Git: git://git.debian.org/git/debian-science/packages/freecad.git
|
Vcs-Git: git://git.debian.org/git/debian-science/packages/freecad.git
|
||||||
Homepage: http://juergen-riegel.net/FreeCAD/Docu/index.php?title=Main_Page
|
Homepage: https://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page
|
||||||
Build-Depends: debhelper (>= 7.0.50~), autotools-dev, libtool, automake,
|
Build-Depends: debhelper (>= 7.0.50~), cmake,
|
||||||
autoconf, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
|
libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
|
||||||
libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev,
|
libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev,
|
||||||
libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev,
|
libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev,
|
||||||
libboost-python-dev, python-dev, python-support,
|
libboost-thread-dev, libboost-python-dev, python-dev, python-support,
|
||||||
libqt4-dev, libxt-dev, libxext-dev, libxmu-dev, libxi-dev, libx11-dev,
|
libqt4-dev, libxt-dev, libxext-dev, libxmu-dev, libxi-dev, libx11-dev,
|
||||||
libcoin60-dev, libsoqt4-dev (>= 1.4.2~svn20090224), libeigen3-dev, libgl1-mesa-dev,
|
libcoin60-dev, libsoqt4-dev, libeigen3-dev,
|
||||||
zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev, libopencascade-modeling-dev,
|
zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev,
|
||||||
|
libopencascade-modeling-dev, libopencascade-ocaf-dev,
|
||||||
libopencascade-visualization-dev, python-cxx-dev, libswscale-dev,
|
libopencascade-visualization-dev, python-cxx-dev, libswscale-dev,
|
||||||
libzipios++-dev, swig, gfortran, libqtwebkit-dev
|
libzipios++-dev, swig, gfortran, f2c, libqtwebkit-dev, libspnav-dev, libfreetype6-dev
|
||||||
Standards-Version: 3.9.2
|
Standards-Version: 3.9.1
|
||||||
|
|
||||||
Package: freecad
|
Package: freecad
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
|
||||||
Recommends: python-pivy python-matplotlib
|
Recommends: python-pivy, python
|
||||||
Suggests: freecad-doc
|
Suggests: freecad-doc
|
||||||
Description: Extensible Open Source CAx program (alpha)
|
Description: Extensible Open Source CAx program (beta)
|
||||||
FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python.
|
FreeCAD is an Open Source CAx RAD based on OpenCasCade, Qt and Python.
|
||||||
It features some key concepts like macro recording, workbenches, ability
|
It features some key concepts like macro recording, workbenches, ability
|
||||||
to run as a server and dynamically loadable application extensions and
|
to run as a server and dynamically loadable application extensions and
|
||||||
|
|
1018
package/debian/diff/freecad_precise.diff
Normal file
1018
package/debian/diff/freecad_precise.diff
Normal file
File diff suppressed because it is too large
Load Diff
8
package/debian/dirs
Normal file
8
package/debian/dirs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
usr/share/icons/hicolor/16x16/apps
|
||||||
|
usr/share/icons/hicolor/32x32/apps
|
||||||
|
usr/share/icons/hicolor/48x48/apps
|
||||||
|
usr/share/icons/hicolor/64x64/apps
|
||||||
|
usr/share/icons/hicolor/scalable/apps
|
||||||
|
usr/share/icons/hicolor/64x64/mimetypes
|
||||||
|
usr/share/pixmaps
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Encoding=UTF-8
|
|
||||||
Type=X-Thumbnailer
|
|
||||||
Name=FreeCAD Thumbnailer
|
|
||||||
MimeType=application/x-extension-fcstd;
|
|
||||||
X-Thumbnailer-Exec=/usr/bin/freecad-thumbnailer %u %o %s
|
|
||||||
GenericName=FreeCADThumbnailer
|
|
1
package/debian/freecad-doc.docs
Normal file
1
package/debian/freecad-doc.docs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debian/tmp/usr/doc/*
|
|
@ -10,7 +10,7 @@ Exec=/usr/bin/freecad %F
|
||||||
Path=/usr/lib/freecad
|
Path=/usr/lib/freecad
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Icon=/usr/share/freecad/freecad.xpm
|
Icon=freecad
|
||||||
Categories=Graphics;Science;Engineering
|
Categories=Graphics;Science;Engineering
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
GenericName[de_DE]=Feature-basierter parametrischer Modellierer
|
GenericName[de_DE]=Feature-basierter parametrischer Modellierer
|
||||||
|
|
1
package/debian/freecad.manpages
Normal file
1
package/debian/freecad.manpages
Normal file
|
@ -0,0 +1 @@
|
||||||
|
debian/freecad.1
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
|
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
|
||||||
<mime-type type="application/x-extension-fcstd">
|
<mime-type type="application/x-extension-fcstd">
|
||||||
<sub-class-of type="application/zip"/>
|
<!-- <sub-class-of type="application/zip"/> -->
|
||||||
<comment>FreeCAD document files</comment>
|
<comment>FreeCAD document files</comment>
|
||||||
<glob pattern="*.fcstd"/>
|
<glob pattern="*.fcstd"/>
|
||||||
</mime-type>
|
</mime-type>
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[Thumbnailer Entry]
|
|
||||||
TryExec=freecad-thumbnailer
|
|
||||||
Exec=freecad-thumbnailer -s %s %u %o
|
|
||||||
MimeType=application/x-extension-fcstd;
|
|
|
@ -2,5 +2,5 @@
|
||||||
section="Applications/Science/Engineering"\
|
section="Applications/Science/Engineering"\
|
||||||
title="FreeCAD"\
|
title="FreeCAD"\
|
||||||
command="/usr/bin/freecad"\
|
command="/usr/bin/freecad"\
|
||||||
icon="/usr/share/freecad/freecad.xpm"
|
icon="/usr/share/pixmaps/freecad.xpm"
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import sys, zipfile, md5
|
import sys, zipfile
|
||||||
import getopt
|
import getopt
|
||||||
import gnomevfs
|
from urlparse import urlparse
|
||||||
|
from urlparse import unquote
|
||||||
|
|
||||||
opt,par = getopt.getopt(sys.argv[1:],'-s:')
|
opt,par = getopt.getopt(sys.argv[1:],'-s:')
|
||||||
inpfile = gnomevfs.get_local_path_from_uri(par[0])
|
uri = urlparse(par[0])
|
||||||
|
if uri.scheme != "file":
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
inpfile = unquote(uri.path)
|
||||||
outfile = par[1]
|
outfile = par[1]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -19,8 +24,9 @@ try:
|
||||||
if image in files:
|
if image in files:
|
||||||
image=zfile.read(image)
|
image=zfile.read(image)
|
||||||
else:
|
else:
|
||||||
freecad=open("/usr/share/freecad/freecad-doc.png")
|
#freecad=open("/usr/share/freecad/freecad-doc.png")
|
||||||
image=freecad.read()
|
#image=freecad.read()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
thumb=open(outfile,"wb")
|
thumb=open(outfile,"wb")
|
||||||
thumb.write(image)
|
thumb.write(image)
|
||||||
|
|
4
package/debian/mime/freecad.thumbnailer
Normal file
4
package/debian/mime/freecad.thumbnailer
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[Thumbnailer Entry]
|
||||||
|
TryExec=/usr/bin/freecad-thumbnailer
|
||||||
|
Exec=/usr/bin/freecad-thumbnailer -s %s %u %o
|
||||||
|
MimeType=application/x-extension-fcstd;
|
|
@ -1,78 +0,0 @@
|
||||||
Index: debian/rules
|
|
||||||
===================================================================
|
|
||||||
--- debian/rules (revision 1523)
|
|
||||||
+++ debian/rules (working copy)
|
|
||||||
@@ -11,6 +11,10 @@
|
|
||||||
|
|
||||||
MODULES = Part Mesh Points Raytracing Image Drawing Test
|
|
||||||
|
|
||||||
+# Preliminary only as long as no official debian package for
|
|
||||||
+# OpenCascade is available
|
|
||||||
+DESTOCCDIR=$(shell pwd)/debian/freecad/usr/lib/freecad/lib
|
|
||||||
+
|
|
||||||
# These are used for cross-compiling and for saving the configure script
|
|
||||||
# from having to guess our platform (since we know it already)
|
|
||||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
|
||||||
@@ -85,6 +89,33 @@
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/FreeCAD.so usr/lib/freecad/lib
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/lib*.so.* usr/lib/freecad/lib
|
|
||||||
|
|
||||||
+# Preliminary only as long as no official debian package for
|
|
||||||
+# OpenCascade is available
|
|
||||||
+ install -m777 /usr/lib/libTKernel-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKMath-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKG2d-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKG3d-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKGeomBase-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKBRep-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKGeomAlgo-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKTopAlgo-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKPrim-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKBO-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKBool-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKShHealing-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKXSBase-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKSTEPBase-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKSTEPAttr-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKSTEP209-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKSTEP-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKFillet-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKOffset-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKIGES-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKMesh-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKHLR-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libTKSTL-6.2.so $(DESTOCCDIR)
|
|
||||||
+ install -m777 /usr/lib/libSoQt4.so.20 $(DESTOCCDIR)
|
|
||||||
+
|
|
||||||
# install the modules
|
|
||||||
$(foreach MODULE,$(MODULES), \
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/$(MODULE)*.so usr/lib/freecad/Mod/$(MODULE); \
|
|
||||||
Index: debian/shlibs.local
|
|
||||||
===================================================================
|
|
||||||
--- debian/shlibs.local (revision 0)
|
|
||||||
+++ debian/shlibs.local (revision 0)
|
|
||||||
@@ -0,0 +1,24 @@
|
|
||||||
+libTKernel 6.2
|
|
||||||
+libTKMath 6.2
|
|
||||||
+libTKG2d 6.2
|
|
||||||
+libTKG3d 6.2
|
|
||||||
+libTKGeomBase 6.2
|
|
||||||
+libTKBRep 6.2
|
|
||||||
+libTKGeomAlgo 6.2
|
|
||||||
+libTKTopAlgo 6.2
|
|
||||||
+libTKPrim 6.2
|
|
||||||
+libTKBO 6.2
|
|
||||||
+libTKBool 6.2
|
|
||||||
+libTKShHealing 6.2
|
|
||||||
+libTKXSBase 6.2
|
|
||||||
+libTKSTEPAttr 6.2
|
|
||||||
+libTKSTEPBase 6.2
|
|
||||||
+libTKSTEP209 6.2
|
|
||||||
+libTKSTEP 6.2
|
|
||||||
+libTKFillet 6.2
|
|
||||||
+libTKOffset 6.2
|
|
||||||
+libTKIGES 6.2
|
|
||||||
+libTKMesh 6.2
|
|
||||||
+libTKHLR 6.2
|
|
||||||
+libTKSTL 6.2
|
|
||||||
+libSoQt4 20
|
|
|
@ -1,33 +0,0 @@
|
||||||
Index: control
|
|
||||||
===================================================================
|
|
||||||
--- control (revision 2213)
|
|
||||||
+++ control (working copy)
|
|
||||||
@@ -4,21 +4,21 @@
|
|
||||||
Maintainer: Werner Mayer <wmayer@users.sourceforge.net>
|
|
||||||
Homepage: http://sourceforge.net/projects/free-cad
|
|
||||||
Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3),
|
|
||||||
- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
|
|
||||||
- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev,
|
|
||||||
- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev,
|
|
||||||
- zlib1g-dev, libxerces27-dev | libxerces-c2-dev,
|
|
||||||
+ libstdc++6, libboost1.37-dev, libboost-date-time1.37-dev, libboost-filesystem1.37-dev,
|
|
||||||
+ libboost-graph1.37-dev, libboost-iostreams1.37-dev, libboost-program-options1.37-dev,
|
|
||||||
+ libboost-regex1.37-dev, libboost-serialization1.37-dev, libboost-signals1.37-dev,
|
|
||||||
+ zlib1g-dev, libxerces-c28 | libxerces-c2-dev,
|
|
||||||
libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev,
|
|
||||||
- libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev,
|
|
||||||
+ libqt4-dev, libsoqt4-dev, libcoin60-dev, libgl1-mesa-dev,
|
|
||||||
python2.5-dev, python, python-central (>= 0.5.6),
|
|
||||||
- libgts-dev, libcv-dev, libopencascade-dev
|
|
||||||
+ libgts-dev, libcv-dev, libopencascade-foundation-dev, libopencascade-modeling-dev
|
|
||||||
Standards-Version: 3.7.3
|
|
||||||
XS-Python-Version: current
|
|
||||||
|
|
||||||
Package: freecad
|
|
||||||
Architecture: any
|
|
||||||
Section: science
|
|
||||||
-Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python
|
|
||||||
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python, python-pivy
|
|
||||||
XB-Python-Version: ${python:Versions}
|
|
||||||
Conflicts: freecad (<= 0.6.472-1)
|
|
||||||
Suggests: gnochm | kchmviewer | kchmviewer-nokde | xchm, python-opencv
|
|
|
@ -1,25 +0,0 @@
|
||||||
Index: debian/control
|
|
||||||
===================================================================
|
|
||||||
--- debian/control (Revision 1881)
|
|
||||||
+++ debian/control (Arbeitskopie)
|
|
||||||
@@ -4,15 +4,15 @@
|
|
||||||
Maintainer: Werner Mayer <wmayer@users.sourceforge.net>
|
|
||||||
Homepage: http://sourceforge.net/projects/free-cad
|
|
||||||
Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3),
|
|
||||||
- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
|
|
||||||
- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev,
|
|
||||||
- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev,
|
|
||||||
- zlib1g-dev, libxerces27-dev | libxerces-c2-dev,
|
|
||||||
+ libstdc++6, libboost1.35-dev, libboost-date-time1.35-dev, libboost-filesystem1.35-dev,
|
|
||||||
+ libboost-graph1.35-dev, libboost-iostreams1.35-dev, libboost-program-options1.35-dev,
|
|
||||||
+ libboost-regex1.35-dev, libboost-serialization1.35-dev, libboost-signals1.35-dev,
|
|
||||||
+ libboost-system1.35-dev, zlib1g-dev, libxerces27-dev | libxerces-c2-dev,
|
|
||||||
libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev,
|
|
||||||
libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev,
|
|
||||||
python2.5-dev, python, python-central (>= 0.5.6),
|
|
||||||
libgts-dev, libcv-dev, libopencascade-dev
|
|
||||||
-Standards-Version: 3.7.3
|
|
||||||
+Standards-Version: 3.8.0
|
|
||||||
XS-Python-Version: current
|
|
||||||
|
|
||||||
Package: freecad
|
|
|
@ -1,25 +0,0 @@
|
||||||
Index: debian/control
|
|
||||||
===================================================================
|
|
||||||
--- debian/control (Revision 1879)
|
|
||||||
+++ debian/control (Arbeitskopie)
|
|
||||||
@@ -4,15 +4,15 @@
|
|
||||||
Maintainer: Werner Mayer <wmayer@users.sourceforge.net>
|
|
||||||
Homepage: http://sourceforge.net/projects/free-cad
|
|
||||||
Build-Depends: debhelper (>= 5), autotools-dev, libc6-dev (>= 2.1.3),
|
|
||||||
- libstdc++6, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
|
|
||||||
- libboost-graph-dev, libboost-iostreams-dev, libboost-program-options-dev,
|
|
||||||
- libboost-regex-dev, libboost-serialization-dev, libboost-signals-dev,
|
|
||||||
- zlib1g-dev, libxerces27-dev | libxerces-c2-dev,
|
|
||||||
+ libstdc++6, libboost1.35-dev, libboost-date-time1.35-dev, libboost-filesystem1.35-dev,
|
|
||||||
+ libboost-graph1.35-dev, libboost-iostreams1.35-dev, libboost-program-options1.35-dev,
|
|
||||||
+ libboost-regex1.35-dev, libboost-serialization1.35-dev, libboost-signals1.35-dev,
|
|
||||||
+ libboost-system1.35-dev, zlib1g-dev, libxerces27-dev | libxerces-c2-dev,
|
|
||||||
libxt-dev, libxmu-dev, libxi-dev, libx11-dev, libxext-dev,
|
|
||||||
libqt4-dev, libsoqt4-dev, libcoin40-dev, libgl1-mesa-dev,
|
|
||||||
python2.5-dev, python, python-central (>= 0.5.6),
|
|
||||||
libgts-dev, libcv-dev, libopencascade-dev
|
|
||||||
-Standards-Version: 3.7.3
|
|
||||||
+Standards-Version: 3.8.0
|
|
||||||
XS-Python-Version: current
|
|
||||||
|
|
||||||
Package: freecad
|
|
|
@ -4,7 +4,7 @@
|
||||||
# Uncomment this to turn on verbose mode.
|
# Uncomment this to turn on verbose mode.
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
MODULES = Part Mesh MeshPart PartDesign Sketcher Points Raytracing Image Drawing ReverseEngineering Complete Fem Robot Import Inspection Arch
|
# For testing: fakeroot debian/rules binary
|
||||||
|
|
||||||
# These are used for cross-compiling and for saving the configure script
|
# These are used for cross-compiling and for saving the configure script
|
||||||
# from having to guess our platform (since we know it already)
|
# from having to guess our platform (since we know it already)
|
||||||
|
@ -19,58 +19,32 @@ else
|
||||||
CFLAGS += -O2
|
CFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
patch-stamp:
|
configure:
|
||||||
touch $@
|
|
||||||
|
|
||||||
configure: autogen.sh patch-stamp
|
|
||||||
dh_testdir
|
dh_testdir
|
||||||
for autotools_mod_file in `find . -name Makefile.in` aclocal.m4 \
|
cmake . \
|
||||||
configure m4/libtool.m4 m4/ltmain.sh m4/ltoptions.m4 \
|
-DFREECAD_BUILD_DEBIAN=ON \
|
||||||
m4/ltversion.m4 m4/lt~obsolete.m4; do \
|
-DCMAKE_INSTALL_PREFIX=/usr/lib/freecad \
|
||||||
cp -a $$autotools_mod_file $$autotools_mod_file.setaside; \
|
-DCMAKE_INSTALL_MANDIR=/usr/share/man \
|
||||||
done
|
-DCMAKE_INSTALL_INFODIR=/usr/share/info \
|
||||||
chmod u+x autogen.sh
|
-DCMAKE_INSTALL_DATADIR=/usr/share/freecad \
|
||||||
./autogen.sh
|
-DCMAKE_INSTALL_INCLUDEDIR=/usr/include/freecad \
|
||||||
|
-DCMAKE_INSTALL_DOCDIR=/usr/share/doc/freecad
|
||||||
config.status: configure
|
|
||||||
dh_testdir
|
|
||||||
./configure --with-occ-include=/usr/include/opencascade \
|
|
||||||
--with-occ-lib=/usr/lib \
|
|
||||||
--host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) \
|
|
||||||
--prefix=/usr/lib/freecad --mandir=/usr/share/man \
|
|
||||||
--infodir=/usr/share/info --datadir=/usr/share/freecad \
|
|
||||||
--includedir=/usr/include/freecad --docdir=/usr/share/doc/freecad \
|
|
||||||
CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs"
|
|
||||||
touch src/Build/Version.h
|
|
||||||
|
|
||||||
build: build-stamp
|
build: build-stamp
|
||||||
|
|
||||||
build-stamp: config.status
|
build-stamp: configure
|
||||||
dh_testdir
|
dh_testdir
|
||||||
$(MAKE)
|
$(MAKE)
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
mv src/Build/Version.h src/Build/Version.h.old
|
|
||||||
dh clean
|
dh clean
|
||||||
mv src/Build/Version.h.old src/Build/Version.h
|
|
||||||
rm -f build-stamp
|
rm -f build-stamp
|
||||||
find -name '*.pyc' | xargs rm -f
|
find -name '*.pyc' | xargs rm -f
|
||||||
find -name 'moc_*.cpp' | xargs rm -f
|
find -name 'moc_*.cpp' | xargs rm -f
|
||||||
find -name '*.lo' | xargs rm -f
|
find -name 'ui_*.h' | xargs rm -f
|
||||||
find -name '*.deps' | xargs rm -rf
|
find -name 'CMakeFiles' | xargs rm -rf
|
||||||
find -name '*.libs' | xargs rm -rf
|
rm -f stamp-h1
|
||||||
rm -f stamp-h1 config.log libtool 71
|
|
||||||
if [ -e Makefile.in.setaside ]; then \
|
|
||||||
for autotools_mod_file in `find . -name Makefile.in` aclocal.m4 \
|
|
||||||
configure m4/libtool.m4 m4/ltmain.sh m4/ltoptions.m4 \
|
|
||||||
m4/ltversion.m4 m4/lt~obsolete.m4; do \
|
|
||||||
mv -f $$autotools_mod_file.setaside $$autotools_mod_file; \
|
|
||||||
done; fi
|
|
||||||
dh clean
|
|
||||||
rm -f patch-stamp
|
|
||||||
#quilt pop -a
|
|
||||||
#rm -rf .pc/
|
|
||||||
|
|
||||||
install: build install-stamp
|
install: build install-stamp
|
||||||
install-stamp:
|
install-stamp:
|
||||||
|
@ -78,44 +52,34 @@ install-stamp:
|
||||||
dh_testroot
|
dh_testroot
|
||||||
dh_prep
|
dh_prep
|
||||||
dh_installdirs
|
dh_installdirs
|
||||||
$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp/freecad
|
$(MAKE) install/fast DESTDIR=$(CURDIR)/debian/tmp/freecad
|
||||||
# Remove testing modules we don't want to have in the deb
|
|
||||||
rm -rf debian/tmp/freecad/usr/lib/freecad/Mod/_TEMPLATE_
|
|
||||||
rm -rf debian/tmp/freecad/usr/lib/freecad/Mod/TemplatePyMod
|
|
||||||
# install the core system
|
# install the core system
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/* usr/share/freecad/
|
dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/* usr/share/freecad/
|
||||||
#dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/share usr/lib/freecad
|
# Desktop icons
|
||||||
|
dh_install -pfreecad debian/tmp/freecad/usr/share/freecad/freecad.xpm usr/share/pixmaps
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-16.png debian/freecad/usr/share/icons/hicolor/16x16/apps/freecad.png
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/32x32/apps/freecad.png
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-32.png debian/freecad/usr/share/icons/hicolor/48x48/apps/freecad.png
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-icon-64.png debian/freecad/usr/share/icons/hicolor/64x64/apps/freecad.png
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad.svg debian/freecad/usr/share/icons/hicolor/scalable/apps/freecad.svg
|
||||||
|
install -m 644 debian/tmp/freecad/usr/share/freecad/freecad-doc.png debian/freecad/usr/share/icons/hicolor/64x64/mimetypes/application-x-extension-fcstd.png
|
||||||
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/bin usr/lib/freecad
|
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/bin usr/lib/freecad
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/FreeCAD.so usr/lib/freecad/lib
|
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib usr/lib/freecad
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/lib/lib*.so.* usr/lib/freecad/lib
|
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod usr/lib/freecad
|
||||||
dh_install debian/freecad.desktop usr/share/applications
|
dh_install debian/freecad.desktop usr/share/applications
|
||||||
dh_installman debian/freecad.1
|
dh_installman debian/freecad.1 debian/mime/freecad-thumbnailer.1
|
||||||
dh_installchangelogs ChangeLog.txt
|
dh_installchangelogs ChangeLog.txt
|
||||||
# install the modules
|
# install the headers
|
||||||
$(foreach MODULE,$(MODULES), \
|
#dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/$(MODULE)*.so usr/lib/freecad/Mod/$(MODULE); \
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.so.* usr/lib/freecad/Mod/$(MODULE); \
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/*.py usr/lib/freecad/Mod/$(MODULE);)
|
|
||||||
# special treating of PartDesign module
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/PartDesign/Scripts/*.py usr/lib/freecad/Mod/PartDesign/Scripts;)
|
|
||||||
# special treating of Draft module
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Draft/*.py usr/lib/freecad/Mod/Draft
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Draft/draftlibs/*.py usr/lib/freecad/Mod/Draft/draftlibs
|
|
||||||
# special treating of Test module
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/lib*.so.* usr/lib/freecad/Mod/Test
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/*.py usr/lib/freecad/Mod/Test
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Test/QtUnitGui.so usr/lib/freecad/Mod/Test
|
|
||||||
|
|
||||||
dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include
|
|
||||||
dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/lib/lib*.so usr/lib/freecad/lib
|
|
||||||
$(foreach MODULE,$(MODULES), \
|
|
||||||
dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.la usr/lib/freecad/Mod/$(MODULE); \
|
|
||||||
dh_install -pfreecad-dev debian/tmp/freecad/usr/lib/freecad/Mod/$(MODULE)/lib*.so usr/lib/freecad/Mod/$(MODULE);)
|
|
||||||
# special treating of Arch module
|
|
||||||
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod/Arch/*.py usr/lib/freecad/Mod/Arch
|
|
||||||
|
|
||||||
# install the help system
|
# install the help system
|
||||||
dh_install -pfreecad-doc debian/tmp/freecad/usr/share/doc/* usr/share/doc/
|
dh_install -pfreecad-doc debian/tmp/freecad/usr/share/doc/* usr/share/doc/
|
||||||
|
# install MIME stuff
|
||||||
|
dh_install debian/mime/freecad-thumbnailer usr/bin
|
||||||
|
dh_install debian/mime/freecad.thumbnailer usr/share/thumbnailers
|
||||||
|
dh_install debian/mime/freecad.schemas etc/gconf/schemas
|
||||||
|
dh_gconf -pfreecad
|
||||||
|
dh_installmime
|
||||||
touch install-stamp
|
touch install-stamp
|
||||||
|
|
||||||
override_dh_compress:
|
override_dh_compress:
|
||||||
|
|
47
package/debian/scripts/get_git_orig_src.sh
Normal file
47
package/debian/scripts/get_git_orig_src.sh
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# The script creates a tar.xz tarball from git-repository of freecad-project
|
||||||
|
# ./get_orig_src.sh commitID - creates a tarball of specified commit
|
||||||
|
# ./get_orig_src.sh - creates a tarball of the latest version
|
||||||
|
# Packages, that needs to be installed to use the script:
|
||||||
|
# atool, git-core
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
git clone git://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad git_temp_packaging
|
||||||
|
|
||||||
|
cd git_temp_packaging
|
||||||
|
|
||||||
|
if [ $1 ]
|
||||||
|
then
|
||||||
|
echo 'Checking out the revision ' $1
|
||||||
|
git checkout -b newvers $1
|
||||||
|
else
|
||||||
|
echo 'Using the latest revision'
|
||||||
|
fi
|
||||||
|
|
||||||
|
GIT_CMT_COUNT=$(git rev-list HEAD | wc -l)
|
||||||
|
|
||||||
|
DEB_VER=0.13.$GIT_CMT_COUNT-dfsg
|
||||||
|
FOLDER_NAME=freecad-$DEB_VER
|
||||||
|
TARBALL_NAME=freecad_$DEB_VER.orig.tar.xz
|
||||||
|
|
||||||
|
echo $DEB_VER
|
||||||
|
echo $FOLDER_NAME
|
||||||
|
echo $TARBALL_NAME
|
||||||
|
|
||||||
|
python src/Tools/SubWCRev.py
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
rm -fr $FOLDER_NAME
|
||||||
|
|
||||||
|
mv git_temp_packaging $FOLDER_NAME
|
||||||
|
rm -rf $FOLDER_NAME/.git
|
||||||
|
rm -rf $FOLDER_NAME/src/3rdParty/CxImage
|
||||||
|
rm -rf $FOLDER_NAME/src/3rdParty/Pivy
|
||||||
|
rm -rf $FOLDER_NAME/src/3rdParty/Pivy-0.5
|
||||||
|
|
||||||
|
tar Jcvf $TARBALL_NAME $FOLDER_NAME
|
||||||
|
|
||||||
|
rm -fr $FOLDER_NAME
|
|
@ -1,2 +0,0 @@
|
||||||
libGL 1 libgl1-mesa-glx (>= 7.7.1-1)
|
|
||||||
libSoQt4 20 libsoqt4-20 (>= 1.4.2~svn20090224)
|
|
|
@ -1 +1 @@
|
||||||
3.0 (quilt)
|
1.0
|
||||||
|
|
|
@ -16,68 +16,36 @@
|
||||||
# http://www.grymoire.com/Unix/Sed.html
|
# http://www.grymoire.com/Unix/Sed.html
|
||||||
|
|
||||||
# global settings
|
# global settings
|
||||||
REV_FILE=./revision.m4
|
|
||||||
TMP_PATH=/tmp
|
TMP_PATH=/tmp
|
||||||
MAJ=0
|
MAJ=0
|
||||||
MIN=12
|
MIN=13
|
||||||
ALIAS="Vulcan"
|
|
||||||
|
|
||||||
# go to root directory
|
# go to root directory
|
||||||
CUR_DIR=$PWD
|
CUR_DIR=$PWD
|
||||||
verz=`dirname $(readlink -f ${0})`
|
verz=`dirname $(readlink -f ${0})`
|
||||||
cd $verz && cd ..
|
cd $verz && cd ..
|
||||||
|
|
||||||
# let's import OLD_REV (if there)
|
# http://blog.marcingil.com/2011/11/creating-build-numbers-using-git-commits/
|
||||||
if [ -f ./.last_revision ]; then
|
if git log -1 >/dev/null 2>&1; then
|
||||||
. ./.last_revision
|
REV=`git rev-list HEAD | wc -l | sed -e 's/ *//g' | xargs -n1 printf %04d`
|
||||||
else
|
|
||||||
OLD_REV=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if svn --xml info >/dev/null 2>&1; then
|
|
||||||
REV=`svn --xml info | tr -d '\r\n' | sed -e 's/.*<commit.*revision="\([0-9]*\)".*<\/commit>.*/\1/'`
|
|
||||||
LCD=`svn --xml info | tr -d '\r\n' | sed -e 's/.*<commit.*<date>\([0-9\-]*\)\T\([0-9\:]*\)\..*<\/date>.*<\/commit>.*/\1 \2/'`
|
|
||||||
URL=`svn --xml info | tr -d '\r\n' | sed -e 's/.*<url>\(.*\)<\/url>.*/\1/'`
|
|
||||||
elif svn --version --quiet >/dev/null 2>&1; then
|
|
||||||
REV=`svn info | grep "^Revision:" | cut -d" " -f2`
|
|
||||||
LCD=`svn info | grep "^Last Changed Date:" | cut -d" " -f4,5`
|
|
||||||
URL=`svn info | grep "^URL:" | cut -d" " -f2`
|
|
||||||
else
|
else
|
||||||
REV=0
|
REV=0
|
||||||
LCD=""
|
|
||||||
URL=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "x$REV" != "x$OLD_REV" -o ! -r $REV_FILE ]; then
|
|
||||||
echo "m4_define([FREECAD_MAJOR], $MAJ)" > $REV_FILE
|
|
||||||
echo "m4_define([FREECAD_MINOR], $MIN)" >> $REV_FILE
|
|
||||||
echo "m4_define([FREECAD_MICRO], $REV)" >> $REV_FILE
|
|
||||||
|
|
||||||
#echo "#define FCVersionMajor \"$MAJ\"" > src/Build/Version.h
|
|
||||||
#echo "#define FCVersionMinor \"$MIN\"" >> src/Build/Version.h
|
|
||||||
#echo "#define FCVersionName \"$ALIAS\"" >> src/Build/Version.h
|
|
||||||
#echo "#define FCRevision \"$REV\"" >> src/Build/Version.h
|
|
||||||
#echo "#define FCRepositoryURL \"$URL\"" >> src/Build/Version.h
|
|
||||||
#echo "#define FCCurrentDateT \"$LCD\"\n" >> src/Build/Version.h
|
|
||||||
touch src/Build/Version.h.in
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "OLD_REV=$REV" > ./.last_revision
|
|
||||||
|
|
||||||
SRC_DIR=$PWD
|
SRC_DIR=$PWD
|
||||||
|
|
||||||
# Prepare source tarball and unpack it in build directory
|
# Prepare source tarball and unpack it in build directory
|
||||||
cd $CUR_DIR
|
cd $CUR_DIR
|
||||||
make dist
|
make dist-git
|
||||||
|
cd $verz && cd ..
|
||||||
rm -rf $TMP_PATH/freecad-$REV
|
rm -rf $TMP_PATH/freecad-$REV
|
||||||
mkdir $TMP_PATH/freecad-$REV
|
mkdir $TMP_PATH/freecad-$REV
|
||||||
mv FreeCAD-$MAJ.$MIN.$REV.tar.gz $TMP_PATH/freecad-$REV/freecad_$MAJ.$MIN.$REV.orig.tar.gz
|
mv freecad-$MAJ.$MIN.$REV.tar.gz $TMP_PATH/freecad-$REV/freecad_$MAJ.$MIN.$REV.orig.tar.gz
|
||||||
cd $TMP_PATH/freecad-$REV
|
cd $TMP_PATH/freecad-$REV
|
||||||
tar -xzf freecad_$MAJ.$MIN.$REV.orig.tar.gz
|
tar -xzf freecad_$MAJ.$MIN.$REV.orig.tar.gz
|
||||||
mv FreeCAD-$MAJ.$MIN.$REV freecad-$MAJ.$MIN.$REV
|
|
||||||
cd freecad-$MAJ.$MIN.$REV
|
cd freecad-$MAJ.$MIN.$REV
|
||||||
rm -rf src/CXX
|
#rm -rf src/CXX
|
||||||
rm -rf src/zipios++
|
#rm -rf src/zipios++
|
||||||
|
|
||||||
# Prepare debian folder and set the revision number in debian/changelog
|
# Prepare debian folder and set the revision number in debian/changelog
|
||||||
# for package versioning
|
# for package versioning
|
||||||
|
|
|
@ -42,9 +42,13 @@
|
||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#include <Standard_Version.hxx>
|
||||||
#include <BRepAdaptor_Curve.hxx>
|
#include <BRepAdaptor_Curve.hxx>
|
||||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||||
#include <BRepTools.hxx>
|
#include <BRepTools.hxx>
|
||||||
|
#if OCC_VERSION_HEX >= 0x060600
|
||||||
|
#include <BRepClass3d.hxx>
|
||||||
|
#endif
|
||||||
#include <TopExp_Explorer.hxx>
|
#include <TopExp_Explorer.hxx>
|
||||||
#include <TopoDS.hxx>
|
#include <TopoDS.hxx>
|
||||||
#include <TopoDS_Shell.hxx>
|
#include <TopoDS_Shell.hxx>
|
||||||
|
@ -159,7 +163,11 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a
|
||||||
|
|
||||||
// get 2 shells
|
// get 2 shells
|
||||||
TopoDS_Solid solid = TopoDS::Solid( aShape );
|
TopoDS_Solid solid = TopoDS::Solid( aShape );
|
||||||
|
#if OCC_VERSION_HEX >= 0x060600
|
||||||
|
TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid );
|
||||||
|
#else
|
||||||
TopoDS_Shell outerShell = BRepTools::OuterShell( solid );
|
TopoDS_Shell outerShell = BRepTools::OuterShell( solid );
|
||||||
|
#endif
|
||||||
TopoDS_Shape innerShell;
|
TopoDS_Shape innerShell;
|
||||||
int nbShells = 0;
|
int nbShells = 0;
|
||||||
for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells )
|
for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells )
|
||||||
|
|
|
@ -1008,7 +1008,10 @@ void Application::initTypes(void)
|
||||||
App ::PropertyPercent ::init();
|
App ::PropertyPercent ::init();
|
||||||
App ::PropertyEnumeration ::init();
|
App ::PropertyEnumeration ::init();
|
||||||
App ::PropertyIntegerList ::init();
|
App ::PropertyIntegerList ::init();
|
||||||
|
App ::PropertyIntegerSet ::init();
|
||||||
|
App ::PropertyMap ::init();
|
||||||
App ::PropertyString ::init();
|
App ::PropertyString ::init();
|
||||||
|
App ::PropertyUUID ::init();
|
||||||
App ::PropertyFont ::init();
|
App ::PropertyFont ::init();
|
||||||
App ::PropertyStringList ::init();
|
App ::PropertyStringList ::init();
|
||||||
App ::PropertyLink ::init();
|
App ::PropertyLink ::init();
|
||||||
|
@ -1213,7 +1216,8 @@ void Application::processCmdLineFiles(void)
|
||||||
else if (File.hasExtension("py")) {
|
else if (File.hasExtension("py")) {
|
||||||
try {
|
try {
|
||||||
Base::Interpreter().loadModule(File.fileNamePure().c_str());
|
Base::Interpreter().loadModule(File.fileNamePure().c_str());
|
||||||
}catch(PyException){
|
}
|
||||||
|
catch(const PyException&) {
|
||||||
// if module load not work, just try run the script (run in __main__)
|
// if module load not work, just try run the script (run in __main__)
|
||||||
Base::Interpreter().runFile(File.filePath().c_str(),true);
|
Base::Interpreter().runFile(File.filePath().c_str(),true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,10 @@ recompute path. Also enables more complicated dependencies beyond trees.
|
||||||
#include <boost/graph/graphviz.hpp>
|
#include <boost/graph/graphviz.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
|
@ -433,9 +437,42 @@ unsigned int Document::getMaxUndoStackSize(void)const
|
||||||
void Document::onChanged(const Property* prop)
|
void Document::onChanged(const Property* prop)
|
||||||
{
|
{
|
||||||
// the Name property is a label for display purposes
|
// the Name property is a label for display purposes
|
||||||
if (prop == &Label)
|
if (prop == &Label) {
|
||||||
App::GetApplication().signalRelabelDocument(*this);
|
App::GetApplication().signalRelabelDocument(*this);
|
||||||
}
|
}
|
||||||
|
else if (prop == &Uid) {
|
||||||
|
std::string new_dir = getTransientDirectoryName(this->Uid.getValueStr(),this->FileName.getStrValue());
|
||||||
|
std::string old_dir = this->TransientDir.getStrValue();
|
||||||
|
Base::FileInfo TransDirNew(new_dir);
|
||||||
|
Base::FileInfo TransDirOld(old_dir);
|
||||||
|
// this directory should not exist
|
||||||
|
if (!TransDirNew.exists()) {
|
||||||
|
if (TransDirOld.exists()) {
|
||||||
|
if (!TransDirOld.renameFile(new_dir.c_str()))
|
||||||
|
Base::Console().Warning("Failed to rename '%s' to '%s'\n", old_dir.c_str(), new_dir.c_str());
|
||||||
|
else
|
||||||
|
this->TransientDir.setValue(new_dir);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!TransDirNew.createDirectory())
|
||||||
|
Base::Console().Warning("Failed to create '%s'\n", new_dir.c_str());
|
||||||
|
else
|
||||||
|
this->TransientDir.setValue(new_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// when reloading an existing document the transient directory doesn't change
|
||||||
|
// so we must avoid to generate a new uuid
|
||||||
|
else if (TransDirNew.filePath() != TransDirOld.filePath()) {
|
||||||
|
// make sure that the uuid is unique
|
||||||
|
std::string uuid = this->Uid.getValueStr();
|
||||||
|
Base::Uuid id;
|
||||||
|
Base::Console().Warning("Document with the UUID '%s' already exists, change to '%s'\n",
|
||||||
|
uuid.c_str(), id.getValue().c_str());
|
||||||
|
// recursive call of onChanged()
|
||||||
|
this->Uid.setValue(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Document::onBeforeChangeProperty(const DocumentObject *Who, const Property *What)
|
void Document::onBeforeChangeProperty(const DocumentObject *Who, const Property *What)
|
||||||
{
|
{
|
||||||
|
@ -525,7 +562,7 @@ Document::Document(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document");
|
ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document");
|
||||||
ADD_PROPERTY_TYPE(FileName,(""),0,Prop_None,"The path to the file where the document is saved to");
|
ADD_PROPERTY_TYPE(FileName,(""),0,Prop_ReadOnly,"The path to the file where the document is saved to");
|
||||||
ADD_PROPERTY_TYPE(CreatedBy,(""),0,Prop_None,"The creator of the document");
|
ADD_PROPERTY_TYPE(CreatedBy,(""),0,Prop_None,"The creator of the document");
|
||||||
ADD_PROPERTY_TYPE(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,Prop_ReadOnly,"Date of creation");
|
ADD_PROPERTY_TYPE(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,Prop_ReadOnly,"Date of creation");
|
||||||
ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,Prop_None,0);
|
ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,Prop_None,0);
|
||||||
|
@ -537,19 +574,16 @@ Document::Document(void)
|
||||||
// create the uuid for the document
|
// create the uuid for the document
|
||||||
Base::Uuid id;
|
Base::Uuid id;
|
||||||
ADD_PROPERTY_TYPE(Id,(""),0,Prop_None,"ID of the document");
|
ADD_PROPERTY_TYPE(Id,(""),0,Prop_None,"ID of the document");
|
||||||
ADD_PROPERTY_TYPE(Uid,(id),0,Prop_None,"UUID of the document");
|
ADD_PROPERTY_TYPE(Uid,(id),0,Prop_ReadOnly,"UUID of the document");
|
||||||
|
|
||||||
// license stuff
|
// license stuff
|
||||||
ADD_PROPERTY_TYPE(License,("CC-BY 3.0"),0,Prop_None,"License string of the Item");
|
ADD_PROPERTY_TYPE(License,("CC-BY 3.0"),0,Prop_None,"License string of the Item");
|
||||||
ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract");
|
ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract");
|
||||||
|
|
||||||
// create transient directory
|
// this creates and sets 'TransientDir' in onChanged()
|
||||||
std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName();
|
ADD_PROPERTY_TYPE(TransientDir,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),
|
||||||
Base::FileInfo TransDir(basePath + "_Doc_" + id.getValue());
|
|
||||||
if (!TransDir.exists())
|
|
||||||
TransDir.createDirectory();
|
|
||||||
ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,Prop_Transient,
|
|
||||||
"Transient directory, where the files live while the document is open");
|
"Transient directory, where the files live while the document is open");
|
||||||
|
Uid.touch();
|
||||||
}
|
}
|
||||||
|
|
||||||
Document::~Document()
|
Document::~Document()
|
||||||
|
@ -574,7 +608,7 @@ Document::~Document()
|
||||||
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
|
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
|
||||||
// Python object or not. In the constructor we forced the wrapper to own the object so we need
|
// Python object or not. In the constructor we forced the wrapper to own the object so we need
|
||||||
// not to dec'ref the Python object any more.
|
// not to dec'ref the Python object any more.
|
||||||
// But we must still invalidate the Python object because it need not to be
|
// But we must still invalidate the Python object because it doesn't need to be
|
||||||
// destructed right now because the interpreter can own several references to it.
|
// destructed right now because the interpreter can own several references to it.
|
||||||
Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
|
Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
|
||||||
// Call before decrementing the reference counter, otherwise a heap error can occur
|
// Call before decrementing the reference counter, otherwise a heap error can occur
|
||||||
|
@ -586,6 +620,19 @@ Document::~Document()
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Document::getTransientDirectoryName(const std::string& uuid, const std::string& filename) const
|
||||||
|
{
|
||||||
|
// Create a directory name of the form: {ExeName}_Doc_{UUID}_{HASH}_{PID}
|
||||||
|
std::stringstream s;
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
|
hash.addData(filename.c_str(), filename.size());
|
||||||
|
s << Base::FileInfo::getTempPath() << GetApplication().getExecutableName()
|
||||||
|
<< "_Doc_" << uuid
|
||||||
|
<< "_" << hash.result().toHex().left(6).constData()
|
||||||
|
<< "_" << QCoreApplication::applicationPid();
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Exported functions
|
// Exported functions
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -623,12 +670,7 @@ void Document::Restore(Base::XMLReader &reader)
|
||||||
std::string FilePath = FileName.getValue();
|
std::string FilePath = FileName.getValue();
|
||||||
std::string DocLabel = Label.getValue();
|
std::string DocLabel = Label.getValue();
|
||||||
|
|
||||||
// remove previous Transient directory
|
// read the Document Properties, when reading in Uid the transient directory gets renamed automatically
|
||||||
Base::FileInfo TransDir(TransientDir.getValue());
|
|
||||||
TransDir.deleteDirectoryRecursive();
|
|
||||||
|
|
||||||
|
|
||||||
// read the Document Properties
|
|
||||||
PropertyContainer::Restore(reader);
|
PropertyContainer::Restore(reader);
|
||||||
|
|
||||||
// We must restore the correct 'FileName' property again because the stored
|
// We must restore the correct 'FileName' property again because the stored
|
||||||
|
@ -636,14 +678,6 @@ void Document::Restore(Base::XMLReader &reader)
|
||||||
FileName.setValue(FilePath.c_str());
|
FileName.setValue(FilePath.c_str());
|
||||||
Label.setValue(DocLabel.c_str());
|
Label.setValue(DocLabel.c_str());
|
||||||
|
|
||||||
// create new transient directory
|
|
||||||
std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName();
|
|
||||||
Base::FileInfo TransDirNew(basePath + "_Doc_" + Uid.getValueStr());
|
|
||||||
if(!TransDirNew.exists())
|
|
||||||
TransDirNew.createDirectory();
|
|
||||||
TransientDir.setValue(TransDirNew.filePath());
|
|
||||||
|
|
||||||
|
|
||||||
// SchemeVersion "2"
|
// SchemeVersion "2"
|
||||||
if ( scheme == 2 ) {
|
if ( scheme == 2 ) {
|
||||||
// read the feature types
|
// read the feature types
|
||||||
|
@ -769,8 +803,8 @@ Document::readObjects(Base::XMLReader& reader)
|
||||||
reader.addName(name.c_str(), obj->getNameInDocument());
|
reader.addName(name.c_str(), obj->getNameInDocument());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Base::Exception&) {
|
catch (const Base::Exception& e) {
|
||||||
Base::Console().Message("Cannot create object '%s'\n", name.c_str());
|
Base::Console().Error("Cannot create object '%s': (%s)\n", name.c_str(), e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reader.readEndElement("Objects");
|
reader.readEndElement("Objects");
|
||||||
|
@ -857,6 +891,18 @@ void Document::exportGraphviz(std::ostream& out)
|
||||||
boost::write_graphviz(out, DepList, boost::make_label_writer(&(names[0])));
|
boost::write_graphviz(out, DepList, boost::make_label_writer(&(names[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Document::saveAs(const char* file)
|
||||||
|
{
|
||||||
|
Base::FileInfo fi(file);
|
||||||
|
if (this->FileName.getStrValue() != file) {
|
||||||
|
this->FileName.setValue(file);
|
||||||
|
this->Label.setValue(fi.fileNamePure());
|
||||||
|
this->Uid.touch(); // this forces a rename of the transient directory
|
||||||
|
}
|
||||||
|
|
||||||
|
return save();
|
||||||
|
}
|
||||||
|
|
||||||
// Save the document under the name it has been opened
|
// Save the document under the name it has been opened
|
||||||
bool Document::save (void)
|
bool Document::save (void)
|
||||||
{
|
{
|
||||||
|
@ -1090,6 +1136,58 @@ std::vector<App::DocumentObject*> Document::getInList(const DocumentObject* me)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<App::DocumentObject*>
|
||||||
|
Document::getDependencyList(const std::vector<App::DocumentObject*>& objs) const
|
||||||
|
{
|
||||||
|
DependencyList DepList;
|
||||||
|
std::map<DocumentObject*,Vertex> ObjectMap;
|
||||||
|
std::map<Vertex,DocumentObject*> VertexMap;
|
||||||
|
|
||||||
|
// Filling up the adjacency List
|
||||||
|
for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
|
||||||
|
// add the object as Vertex and remember the index
|
||||||
|
Vertex v = add_vertex(DepList);
|
||||||
|
ObjectMap[It->second] = v;
|
||||||
|
VertexMap[v] = It->second;
|
||||||
|
}
|
||||||
|
// add the edges
|
||||||
|
for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
|
||||||
|
std::vector<DocumentObject*> OutList = It->second->getOutList();
|
||||||
|
for (std::vector<DocumentObject*>::const_iterator It2=OutList.begin();It2!=OutList.end();++It2) {
|
||||||
|
if (*It2)
|
||||||
|
add_edge(ObjectMap[It->second],ObjectMap[*It2],DepList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Vertex> make_order;
|
||||||
|
DependencyList::out_edge_iterator j, jend;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this sort gives the execute
|
||||||
|
boost::topological_sort(DepList, std::front_inserter(make_order));
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
return std::vector<App::DocumentObject*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::vector<App::DocumentObject*> out;
|
||||||
|
boost::unordered_set<App::DocumentObject*> out;
|
||||||
|
for (std::vector<App::DocumentObject*>::const_iterator it = objs.begin(); it != objs.end(); ++it) {
|
||||||
|
std::map<DocumentObject*,Vertex>::iterator jt = ObjectMap.find(*it);
|
||||||
|
// ok, object is part of this graph
|
||||||
|
if (jt != ObjectMap.end()) {
|
||||||
|
for (boost::tie(j, jend) = boost::out_edges(jt->second, DepList); j != jend; ++j) {
|
||||||
|
out.insert(VertexMap[boost::target(*j, DepList)]);
|
||||||
|
}
|
||||||
|
out.insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<App::DocumentObject*> ary;
|
||||||
|
ary.insert(ary.end(), out.begin(), out.end());
|
||||||
|
return ary;
|
||||||
|
}
|
||||||
|
|
||||||
void Document::_rebuildDependencyList(void)
|
void Document::_rebuildDependencyList(void)
|
||||||
{
|
{
|
||||||
d->VertexObjectList.clear();
|
d->VertexObjectList.clear();
|
||||||
|
@ -1119,21 +1217,6 @@ void Document::recompute()
|
||||||
// updates the dependency graph
|
// updates the dependency graph
|
||||||
_rebuildDependencyList();
|
_rebuildDependencyList();
|
||||||
|
|
||||||
//DependencyList DepList;
|
|
||||||
//std::map<DocumentObject*,Vertex> VertexObjectList;
|
|
||||||
|
|
||||||
//// Filling up the adjacency List
|
|
||||||
//for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It)
|
|
||||||
// // add the object as Vertex and remember the index
|
|
||||||
// VertexObjectList[It->second] = add_vertex(DepList);
|
|
||||||
//// add the edges
|
|
||||||
//for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
|
|
||||||
// std::vector<DocumentObject*> OutList = It->second->getOutList();
|
|
||||||
// for (std::vector<DocumentObject*>::const_iterator It2=OutList.begin();It2!=OutList.end();++It2)
|
|
||||||
// if (*It2)
|
|
||||||
// add_edge(VertexObjectList[It->second],VertexObjectList[*It2],DepList);
|
|
||||||
//}
|
|
||||||
|
|
||||||
std::list<Vertex> make_order;
|
std::list<Vertex> make_order;
|
||||||
DependencyList::out_edge_iterator j, jend;
|
DependencyList::out_edge_iterator j, jend;
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,7 @@ public:
|
||||||
//void saveAs (const char* Name);
|
//void saveAs (const char* Name);
|
||||||
/// Save the document to the file in Property Path
|
/// Save the document to the file in Property Path
|
||||||
bool save (void);
|
bool save (void);
|
||||||
|
bool saveAs(const char* file);
|
||||||
/// Restore the document from the file in Property Path
|
/// Restore the document from the file in Property Path
|
||||||
void restore (void);
|
void restore (void);
|
||||||
void exportObjects(const std::vector<App::DocumentObject*>&, std::ostream&);
|
void exportObjects(const std::vector<App::DocumentObject*>&, std::ostream&);
|
||||||
|
@ -264,6 +265,10 @@ public:
|
||||||
bool checkOnCycle(void);
|
bool checkOnCycle(void);
|
||||||
/// get a list of all objects linking to the given object
|
/// get a list of all objects linking to the given object
|
||||||
std::vector<App::DocumentObject*> getInList(const DocumentObject* me) const;
|
std::vector<App::DocumentObject*> getInList(const DocumentObject* me) const;
|
||||||
|
/// Get a complete list of all objects the given objects depend on. The list
|
||||||
|
/// also contains the given objects!
|
||||||
|
std::vector<App::DocumentObject*> getDependencyList
|
||||||
|
(const std::vector<App::DocumentObject*>&) const;
|
||||||
// set Changed
|
// set Changed
|
||||||
//void setChanged(DocumentObject* change);
|
//void setChanged(DocumentObject* change);
|
||||||
//@}
|
//@}
|
||||||
|
@ -303,6 +308,7 @@ protected:
|
||||||
void _clearRedos();
|
void _clearRedos();
|
||||||
/// refresh the internal dependency graph
|
/// refresh the internal dependency graph
|
||||||
void _rebuildDependencyList(void);
|
void _rebuildDependencyList(void);
|
||||||
|
std::string getTransientDirectoryName(const std::string& uuid, const std::string& filename) const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -38,6 +38,15 @@ namespace App
|
||||||
class Document;
|
class Document;
|
||||||
class DocumentObjectPy;
|
class DocumentObjectPy;
|
||||||
|
|
||||||
|
enum ObjectStatus {
|
||||||
|
Touch = 0,
|
||||||
|
Error = 1,
|
||||||
|
New = 2,
|
||||||
|
Recompute = 3,
|
||||||
|
Restore = 4,
|
||||||
|
Expand = 16
|
||||||
|
};
|
||||||
|
|
||||||
/** Return object for feature execution
|
/** Return object for feature execution
|
||||||
*/
|
*/
|
||||||
class AppExport DocumentObjectExecReturn
|
class AppExport DocumentObjectExecReturn
|
||||||
|
@ -105,6 +114,8 @@ public:
|
||||||
virtual App::DocumentObjectExecReturn *recompute(void);
|
virtual App::DocumentObjectExecReturn *recompute(void);
|
||||||
/// return the status bits
|
/// return the status bits
|
||||||
unsigned long getStatus() const {return StatusBits.to_ulong();}
|
unsigned long getStatus() const {return StatusBits.to_ulong();}
|
||||||
|
bool testStatus(ObjectStatus pos) const {return StatusBits.test((size_t)pos);}
|
||||||
|
void setStatus(ObjectStatus pos, bool on) {StatusBits.set((size_t)pos, on);}
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/// returns a list of objects this object is pointing to by Links
|
/// returns a list of objects this object is pointing to by Links
|
||||||
|
@ -129,7 +140,7 @@ public:
|
||||||
|
|
||||||
/** Called in case of loosing a link
|
/** Called in case of loosing a link
|
||||||
* Get called by the document when a object got deleted a link property of this
|
* Get called by the document when a object got deleted a link property of this
|
||||||
* object ist pointing to. The standard behaivour of the DocumentObject implementation
|
* object ist pointing to. The standard behaviour of the DocumentObject implementation
|
||||||
* is to reset the links to nothing. You may overide this method to implement
|
* is to reset the links to nothing. You may overide this method to implement
|
||||||
*additional or different behavior.
|
*additional or different behavior.
|
||||||
*/
|
*/
|
||||||
|
@ -168,6 +179,7 @@ protected:
|
||||||
* 5 - reserved
|
* 5 - reserved
|
||||||
* 6 - reserved
|
* 6 - reserved
|
||||||
* 7 - reserved
|
* 7 - reserved
|
||||||
|
* 16 - object is marked as 'expanded' in the tree view
|
||||||
*/
|
*/
|
||||||
std::bitset<32> StatusBits;
|
std::bitset<32> StatusBits;
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ void DocumentObserverPython::slotActivateDocument(const App::Document& Doc)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +206,6 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj,
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("%s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,17 @@
|
||||||
</Documentation>
|
</Documentation>
|
||||||
<Methode Name="save">
|
<Methode Name="save">
|
||||||
<Documentation>
|
<Documentation>
|
||||||
<UserDocu>Save the document to disc</UserDocu>
|
<UserDocu>Save the document to disk</UserDocu>
|
||||||
|
</Documentation>
|
||||||
|
</Methode>
|
||||||
|
<Methode Name="saveAs">
|
||||||
|
<Documentation>
|
||||||
|
<UserDocu>Save the document under a new name to disk</UserDocu>
|
||||||
</Documentation>
|
</Documentation>
|
||||||
</Methode>
|
</Methode>
|
||||||
<Methode Name="restore">
|
<Methode Name="restore">
|
||||||
<Documentation>
|
<Documentation>
|
||||||
<UserDocu>Restore the document from disc</UserDocu>
|
<UserDocu>Restore the document from disk</UserDocu>
|
||||||
</Documentation>
|
</Documentation>
|
||||||
</Methode>
|
</Methode>
|
||||||
<Methode Name="exportGraphviz">
|
<Methode Name="exportGraphviz">
|
||||||
|
|
|
@ -69,6 +69,25 @@ PyObject* DocumentPy::save(PyObject * args)
|
||||||
Py_Return;
|
Py_Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* DocumentPy::saveAs(PyObject * args)
|
||||||
|
{
|
||||||
|
char* fn;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &fn)) // convert args: Python->C
|
||||||
|
return NULL; // NULL triggers exception
|
||||||
|
if (!getDocumentPtr()->saveAs(fn)) {
|
||||||
|
PyErr_Format(PyExc_ValueError, "Object attribute 'FileName' is not set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Base::FileInfo fi(fn);
|
||||||
|
if (!fi.isReadable()) {
|
||||||
|
PyErr_Format(PyExc_IOError, "No such file or directory: '%s'", fn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_Return;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject* DocumentPy::restore(PyObject * args)
|
PyObject* DocumentPy::restore(PyObject * args)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
|
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
|
||||||
|
|
|
@ -67,6 +67,7 @@ DocumentObjectExecReturn *FeaturePythonImp::execute()
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
|
e.ReportException();
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << object->Label.getValue() << ": " << e.what();
|
str << object->Label.getValue() << ": " << e.what();
|
||||||
return new App::DocumentObjectExecReturn(str.str());
|
return new App::DocumentObjectExecReturn(str.str());
|
||||||
|
@ -104,8 +105,7 @@ void FeaturePythonImp::onChanged(const Property* prop)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Error("FeaturePython::onChanged (%s): %s\n",
|
e.ReportException();
|
||||||
object->Label.getValue(), e.what());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual unsigned int getMemSize (void) const {
|
virtual unsigned int getMemSize (void) const {
|
||||||
// you have to implement this method in all property classes!
|
// you have to implement this method in all property classes!
|
||||||
return Base::Persistence::getMemSize() + sizeof(father) + sizeof(StatusBits);
|
return sizeof(father) + sizeof(StatusBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the name of this property in the belonging container
|
/// get the name of this property in the belonging container
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "PreCompiled.h"
|
#include "PreCompiled.h"
|
||||||
|
|
||||||
#ifndef _PreComp_
|
#ifndef _PreComp_
|
||||||
|
# include <algorithm>
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -35,12 +36,13 @@
|
||||||
#include <Base/Stream.h>
|
#include <Base/Stream.h>
|
||||||
#include <Base/Console.h>
|
#include <Base/Console.h>
|
||||||
#include <Base/PyObjectBase.h>
|
#include <Base/PyObjectBase.h>
|
||||||
|
#include <Base/Uuid.h>
|
||||||
|
|
||||||
#include "PropertyFile.h"
|
#include "PropertyFile.h"
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
#include "PropertyContainer.h"
|
#include "PropertyContainer.h"
|
||||||
#include "DocumentObject.h"
|
#include "DocumentObject.h"
|
||||||
#define new DEBUG_CLIENTBLOCK
|
|
||||||
using namespace App;
|
using namespace App;
|
||||||
using namespace Base;
|
using namespace Base;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -53,6 +55,7 @@ using namespace std;
|
||||||
|
|
||||||
TYPESYSTEM_SOURCE(App::PropertyFileIncluded , App::Property);
|
TYPESYSTEM_SOURCE(App::PropertyFileIncluded , App::Property);
|
||||||
|
|
||||||
|
|
||||||
PropertyFileIncluded::PropertyFileIncluded()
|
PropertyFileIncluded::PropertyFileIncluded()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -63,17 +66,45 @@ PropertyFileIncluded::~PropertyFileIncluded()
|
||||||
// clean up
|
// clean up
|
||||||
if (!_cValue.empty()) {
|
if (!_cValue.empty()) {
|
||||||
Base::FileInfo file(_cValue.c_str());
|
Base::FileInfo file(_cValue.c_str());
|
||||||
|
file.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
file.deleteFile();
|
file.deleteFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropertyFileIncluded::aboutToSetValue(void)
|
||||||
|
{
|
||||||
|
// This is a trick to check in Copy() if it is called
|
||||||
|
// directly from outside or by the Undo/Redo mechanism.
|
||||||
|
// In the latter case it is sufficient to rename the file
|
||||||
|
// because another file will be assigned afterwards.
|
||||||
|
// If Copy() is directly called (e.g. to copy the file to
|
||||||
|
// another document) a copy of the file needs to be created.
|
||||||
|
// This copy will be deleted again in the class destructor.
|
||||||
|
this->StatusBits.set(10);
|
||||||
|
Property::aboutToSetValue();
|
||||||
|
this->StatusBits.reset(10);
|
||||||
|
}
|
||||||
|
|
||||||
std::string PropertyFileIncluded::getDocTransientPath(void) const
|
std::string PropertyFileIncluded::getDocTransientPath(void) const
|
||||||
{
|
{
|
||||||
|
std::string path;
|
||||||
PropertyContainer *co = getContainer();
|
PropertyContainer *co = getContainer();
|
||||||
if (co->isDerivedFrom(DocumentObject::getClassTypeId()))
|
if (co->isDerivedFrom(DocumentObject::getClassTypeId())) {
|
||||||
return dynamic_cast<DocumentObject*>(co)->getDocument()->TransientDir.getValue();
|
path = dynamic_cast<DocumentObject*>(co)->getDocument()->TransientDir.getValue();
|
||||||
|
std::replace(path.begin(), path.end(), '\\', '/');
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
return std::string();
|
std::string PropertyFileIncluded::getUniqueFileName(const std::string& path, const std::string& filename) const
|
||||||
|
{
|
||||||
|
Base::Uuid uuid;
|
||||||
|
Base::FileInfo fi(path + "/" + filename);
|
||||||
|
while (fi.exists()) {
|
||||||
|
fi.setFile(path + "/" + filename + "." + uuid.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.filePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PropertyFileIncluded::getExchangeTempFile(void) const
|
std::string PropertyFileIncluded::getExchangeTempFile(void) const
|
||||||
|
@ -97,34 +128,40 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutToSetValue(); // undo redo by move the file away with temp name
|
aboutToSetValue(); // undo/redo by moving the file away with temp name
|
||||||
|
|
||||||
// remove old file (if not moved by undo)
|
// remove old file (if not moved by undo)
|
||||||
Base::FileInfo value(_cValue);
|
Base::FileInfo value(_cValue);
|
||||||
std::string pathAct = value.dirPath();
|
std::string pathAct = value.dirPath();
|
||||||
if (value.exists())
|
if (value.exists()) {
|
||||||
|
value.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
value.deleteFile();
|
value.deleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
// if a special name given, use this instead
|
// if a special name given, use this instead
|
||||||
if (sName) {
|
if (sName) {
|
||||||
Base::FileInfo ExtraName(path + "/" + sName);
|
Base::FileInfo fi(pathTrans + "/" + sName);
|
||||||
if (ExtraName.exists() ) {
|
if (fi.exists()) {
|
||||||
// if a file with this name already exists search for a new one
|
// if a file with this name already exists search for a new one
|
||||||
|
std::string dir = pathTrans;
|
||||||
|
std::string fnp = fi.fileNamePure();
|
||||||
|
std::string ext = fi.extension(false);
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
i++;
|
i++;
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << path << "/" << sName << i;
|
str << dir << "/" << fnp << i;
|
||||||
ExtraName.setFile(str.str());
|
if (!ext.empty())
|
||||||
|
str << "." << ext;
|
||||||
|
fi.setFile(str.str());
|
||||||
}
|
}
|
||||||
while (ExtraName.exists());
|
while (fi.exists());
|
||||||
_cValue = ExtraName.filePath();
|
|
||||||
_BaseFileName = ExtraName.fileName();
|
|
||||||
|
|
||||||
|
_cValue = fi.filePath();
|
||||||
|
_BaseFileName = fi.fileName();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_cValue = path + "/" + sName;
|
_cValue = pathTrans + "/" + sName;
|
||||||
_BaseFileName = sName;
|
_BaseFileName = sName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,39 +170,61 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
|
||||||
_BaseFileName = file.fileName();
|
_BaseFileName = file.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the files is already in transient dir of the document, just use it
|
// The following applies only on files that are inside the transient
|
||||||
if (path == pathTrans) {
|
// directory:
|
||||||
|
// When a file is read-only it is supposed to be assigned to a
|
||||||
|
// PropertyFileIncluded instance. In this case we must copy the
|
||||||
|
// file because otherwise the above instance looses its data.
|
||||||
|
// If the file is writable it is supposed to be of free use and
|
||||||
|
// it can be simply renamed.
|
||||||
|
|
||||||
|
// if the file is already in transient dir of the document, just use it
|
||||||
|
if (path == pathTrans && file.isWritable()) {
|
||||||
bool done = file.renameFile(_cValue.c_str());
|
bool done = file.renameFile(_cValue.c_str());
|
||||||
//assert(done);
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "Cannot rename file " << file.filePath() << " to " << _cValue;
|
str << "Cannot rename file " << file.filePath() << " to " << _cValue;
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make the file read-only
|
||||||
|
Base::FileInfo dst(_cValue);
|
||||||
|
dst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
}
|
}
|
||||||
// otherwise copy from origin location
|
// otherwise copy from origin location
|
||||||
else {
|
else {
|
||||||
// if file already exists in transient dir make a new unique name
|
// if file already exists in transient dir make a new unique name
|
||||||
Base::FileInfo fi(_cValue);
|
Base::FileInfo fi(_cValue);
|
||||||
if (fi.exists()) {
|
if (fi.exists()) {
|
||||||
Base::FileInfo fi2(Base::FileInfo::getTempFileName());
|
// if a file with this name already exists search for a new one
|
||||||
std::stringstream str;
|
std::string dir = fi.dirPath();
|
||||||
str << fi.dirPath() << "/" << fi2.fileNamePure();
|
std::string fnp = fi.fileNamePure();
|
||||||
std::string ext = fi.extension(false);
|
std::string ext = fi.extension(false);
|
||||||
|
int i=0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
std::stringstream str;
|
||||||
|
str << dir << "/" << fnp << i;
|
||||||
if (!ext.empty())
|
if (!ext.empty())
|
||||||
str << "." << ext;
|
str << "." << ext;
|
||||||
Base::FileInfo fi3(str.str());
|
fi.setFile(str.str());
|
||||||
_cValue = fi3.filePath();
|
}
|
||||||
_BaseFileName = fi3.fileName();
|
while (fi.exists());
|
||||||
|
|
||||||
|
_cValue = fi.filePath();
|
||||||
|
_BaseFileName = fi.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool done = file.copyTo(_cValue.c_str());
|
bool done = file.copyTo(_cValue.c_str());
|
||||||
//assert(done);
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "Cannot copy file from " << file.filePath() << " to " << _cValue;
|
str << "Cannot copy file from " << file.filePath() << " to " << _cValue;
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make the file read-only
|
||||||
|
Base::FileInfo dst(_cValue);
|
||||||
|
dst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
|
@ -180,7 +239,7 @@ const char* PropertyFileIncluded::getValue(void) const
|
||||||
PyObject *PropertyFileIncluded::getPyObject(void)
|
PyObject *PropertyFileIncluded::getPyObject(void)
|
||||||
{
|
{
|
||||||
PyObject *p = PyUnicode_DecodeUTF8(_cValue.c_str(),_cValue.size(),0);
|
PyObject *p = PyUnicode_DecodeUTF8(_cValue.c_str(),_cValue.size(),0);
|
||||||
if (!p) throw Base::Exception("UTF8 conversion failure at PropertyString::getPyObject()");
|
if (!p) throw Base::Exception("PropertyFileIncluded: UTF-8 conversion failure");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +260,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
|
||||||
}
|
}
|
||||||
else if (PyTuple_Check(value)) {
|
else if (PyTuple_Check(value)) {
|
||||||
if (PyTuple_Size(value) != 2)
|
if (PyTuple_Size(value) != 2)
|
||||||
throw Py::TypeError("Tuple need size of (filePath,newFileName)");
|
throw Base::TypeError("Tuple needs size of (filePath,newFileName)");
|
||||||
PyObject* file = PyTuple_GetItem(value,0);
|
PyObject* file = PyTuple_GetItem(value,0);
|
||||||
PyObject* name = PyTuple_GetItem(value,1);
|
PyObject* name = PyTuple_GetItem(value,1);
|
||||||
|
|
||||||
|
@ -220,9 +279,9 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
|
||||||
fileStr = PyString_AsString(FileName);
|
fileStr = PyString_AsString(FileName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("first in tuple must be a file or string");
|
std::string error = std::string("First item in tuple must be a file or string");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// decoding name
|
// decoding name
|
||||||
|
@ -235,19 +294,18 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
|
||||||
nameStr = PyString_AsString(FileName);
|
nameStr = PyString_AsString(FileName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("second in tuple must be a string");
|
std::string error = std::string("Second item in tuple must be a string");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(fileStr.c_str(),nameStr.c_str());
|
setValue(fileStr.c_str(),nameStr.c_str());
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be str or file");
|
std::string error = std::string("Type must be string or file");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign the string
|
// assign the string
|
||||||
|
@ -256,31 +314,41 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
|
||||||
|
|
||||||
void PropertyFileIncluded::Save (Base::Writer &writer) const
|
void PropertyFileIncluded::Save (Base::Writer &writer) const
|
||||||
{
|
{
|
||||||
|
// when saving a document under a new file name the transient directory
|
||||||
|
// name changes and thus the stored file name doesn't work any more.
|
||||||
|
if (!_cValue.empty() && !Base::FileInfo(_cValue).exists()) {
|
||||||
|
Base::FileInfo fi(getDocTransientPath() + "/" + _BaseFileName);
|
||||||
|
if (fi.exists())
|
||||||
|
_cValue = fi.filePath();
|
||||||
|
}
|
||||||
|
|
||||||
if (writer.isForceXML()) {
|
if (writer.isForceXML()) {
|
||||||
if (!_cValue.empty()) {
|
if (!_cValue.empty()) {
|
||||||
Base::FileInfo file(_cValue.c_str());
|
Base::FileInfo file(_cValue.c_str());
|
||||||
writer.Stream() << writer.ind() << "<FileIncluded data=\"" <<
|
writer.Stream() << writer.ind() << "<FileIncluded data=\""
|
||||||
file.fileName() << "\">" << std::endl;
|
<< file.fileName() << "\">" << std::endl;
|
||||||
// write the file in the XML stream
|
// write the file in the XML stream
|
||||||
writer.incInd();
|
writer.incInd();
|
||||||
writer.insertBinFile(_cValue.c_str());
|
writer.insertBinFile(_cValue.c_str());
|
||||||
writer.decInd();
|
writer.decInd();
|
||||||
writer.Stream() << writer.ind() <<"</FileIncluded>" << endl;
|
writer.Stream() << writer.ind() <<"</FileIncluded>" << endl;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>" << std::endl;
|
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>" << std::endl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// instead initiate an extra file
|
// instead initiate an extra file
|
||||||
if (!_cValue.empty()) {
|
if (!_cValue.empty()) {
|
||||||
Base::FileInfo file(_cValue.c_str());
|
Base::FileInfo file(_cValue.c_str());
|
||||||
writer.Stream() << writer.ind() << "<FileIncluded file=\"" <<
|
writer.Stream() << writer.ind() << "<FileIncluded file=\""
|
||||||
writer.addFile(file.fileName().c_str(), this) << "\"/>" << std::endl;
|
<< writer.addFile(file.fileName().c_str(), this) << "\"/>" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
writer.Stream() << writer.ind() << "<FileIncluded file=\"\"/>" << std::endl;
|
writer.Stream() << writer.ind() << "<FileIncluded file=\"\"/>" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
||||||
{
|
{
|
||||||
|
@ -307,6 +375,9 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
||||||
reader.readBinFile(_cValue.c_str());
|
reader.readBinFile(_cValue.c_str());
|
||||||
reader.readEndElement("FileIncluded");
|
reader.readEndElement("FileIncluded");
|
||||||
_BaseFileName = file;
|
_BaseFileName = file;
|
||||||
|
// set read-only after restoring the file
|
||||||
|
Base::FileInfo fi(_cValue.c_str());
|
||||||
|
fi.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,9 +386,12 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
||||||
void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
|
void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
|
||||||
{
|
{
|
||||||
Base::ifstream from(Base::FileInfo(_cValue.c_str()));
|
Base::ifstream from(Base::FileInfo(_cValue.c_str()));
|
||||||
if (!from)
|
if (!from) {
|
||||||
throw Base::Exception("PropertyFileIncluded::SaveDocFile() "
|
std::stringstream str;
|
||||||
"File in document transient dir deleted");
|
str << "PropertyFileIncluded::SaveDocFile(): "
|
||||||
|
<< "File '" << _cValue << "' in transient directory doesn't exist.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
|
||||||
// copy plain data
|
// copy plain data
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
@ -329,10 +403,14 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
|
||||||
|
|
||||||
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||||
{
|
{
|
||||||
Base::ofstream to(Base::FileInfo(_cValue.c_str()));
|
Base::FileInfo fi(_cValue.c_str());
|
||||||
if (!to)
|
Base::ofstream to(fi);
|
||||||
throw Base::Exception("PropertyFileIncluded::RestoreDocFile() "
|
if (!to) {
|
||||||
"File in document transient dir deleted");
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::RestoreDocFile(): "
|
||||||
|
<< "File '" << _cValue << "' in transient directory doesn't exist.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
|
||||||
// copy plain data
|
// copy plain data
|
||||||
aboutToSetValue();
|
aboutToSetValue();
|
||||||
|
@ -341,6 +419,9 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||||
to.put((const char)c);
|
to.put((const char)c);
|
||||||
}
|
}
|
||||||
to.close();
|
to.close();
|
||||||
|
|
||||||
|
// set read-only after restoring the file
|
||||||
|
fi.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,18 +432,39 @@ Property *PropertyFileIncluded::Copy(void) const
|
||||||
// remember the base name
|
// remember the base name
|
||||||
prop->_BaseFileName = _BaseFileName;
|
prop->_BaseFileName = _BaseFileName;
|
||||||
|
|
||||||
if (!_cValue.empty()) {
|
|
||||||
Base::FileInfo file(_cValue);
|
Base::FileInfo file(_cValue);
|
||||||
|
if (file.exists()) {
|
||||||
// create a new name in the document transient directory
|
// create a new name in the document transient directory
|
||||||
Base::FileInfo NewName(Base::FileInfo::getTempFileName(file.fileName().c_str(),file.dirPath().c_str()));
|
Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName()));
|
||||||
NewName.deleteFile();
|
if (this->StatusBits.test(10)) {
|
||||||
// move the file
|
// rename the file
|
||||||
bool done = file.renameFile(NewName.filePath().c_str());
|
bool done = file.renameFile(newName.filePath().c_str());
|
||||||
assert(done);
|
if (!done) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Copy(): "
|
||||||
|
<< "Renaming the file '" << file.filePath() << "' to '"
|
||||||
|
<< newName.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// copy the file
|
||||||
|
bool done = file.copyTo(newName.filePath().c_str());
|
||||||
|
if (!done) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Copy(): "
|
||||||
|
<< "Copying the file '" << file.filePath() << "' to '"
|
||||||
|
<< newName.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remember the new name for the Undo
|
// remember the new name for the Undo
|
||||||
Base::Console().Log("Copy this=%p Before=%s After=%s\n",prop,prop->_cValue.c_str(),NewName.filePath().c_str());
|
Base::Console().Log("Copy '%s' to '%s'\n",_cValue.c_str(),newName.filePath().c_str());
|
||||||
prop->_cValue = NewName.filePath().c_str();
|
prop->_cValue = newName.filePath().c_str();
|
||||||
|
|
||||||
|
// make backup files writable to avoid copying them again on undo/redo
|
||||||
|
newName.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
|
@ -371,26 +473,65 @@ Property *PropertyFileIncluded::Copy(void) const
|
||||||
void PropertyFileIncluded::Paste(const Property &from)
|
void PropertyFileIncluded::Paste(const Property &from)
|
||||||
{
|
{
|
||||||
aboutToSetValue();
|
aboutToSetValue();
|
||||||
Base::FileInfo file(_cValue);
|
const PropertyFileIncluded &prop = dynamic_cast<const PropertyFileIncluded&>(from);
|
||||||
|
// make sure that source and destination file are different
|
||||||
|
if (_cValue != prop._cValue) {
|
||||||
// delete old file (if still there)
|
// delete old file (if still there)
|
||||||
file.deleteFile();
|
Base::FileInfo fi(_cValue);
|
||||||
const PropertyFileIncluded &fileInc = dynamic_cast<const PropertyFileIncluded&>(from);
|
fi.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
|
fi.deleteFile();
|
||||||
|
|
||||||
|
// get path to destination which can be the transient directory
|
||||||
|
// of another document
|
||||||
|
std::string pathTrans = getDocTransientPath();
|
||||||
|
Base::FileInfo fiSrc(prop._cValue);
|
||||||
|
Base::FileInfo fiDst(pathTrans + "/" + prop._BaseFileName);
|
||||||
|
std::string path = fiSrc.dirPath();
|
||||||
|
|
||||||
|
if (fiSrc.exists()) {
|
||||||
|
fiDst.setFile(getUniqueFileName(fiDst.dirPath(), fiDst.fileName()));
|
||||||
|
|
||||||
|
// if the file is already in transient dir of the document, just use it
|
||||||
|
if (path == pathTrans) {
|
||||||
|
if (!fiSrc.renameFile(fiDst.filePath().c_str())) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Paste(): "
|
||||||
|
<< "Renaming the file '" << fiSrc.filePath() << "' to '"
|
||||||
|
<< fiDst.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!fiSrc.copyTo(fiDst.filePath().c_str())) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Paste(): "
|
||||||
|
<< "Copying the file '" << fiSrc.filePath() << "' to '"
|
||||||
|
<< fiDst.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the file again read-only
|
||||||
|
fiDst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
|
_cValue = fiDst.filePath();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_cValue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// set the base name
|
// set the base name
|
||||||
_BaseFileName = fileInc._BaseFileName;
|
_BaseFileName = prop._BaseFileName;
|
||||||
|
|
||||||
if (!fileInc._cValue.empty()) {
|
|
||||||
// move the saved files back in place
|
|
||||||
Base::FileInfo NewFile(fileInc._cValue);
|
|
||||||
_cValue = NewFile.dirPath() + "/" + fileInc._BaseFileName;
|
|
||||||
bool done = NewFile.renameFile(_cValue.c_str());
|
|
||||||
assert(done);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
_cValue.clear();
|
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int PropertyFileIncluded::getMemSize (void) const
|
||||||
|
{
|
||||||
|
unsigned int mem = Property::getMemSize();
|
||||||
|
mem += _cValue.size();
|
||||||
|
mem += _BaseFileName.size();
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
// PropertyFile
|
// PropertyFile
|
||||||
|
|
|
@ -95,9 +95,7 @@ public:
|
||||||
|
|
||||||
virtual Property *Copy(void) const;
|
virtual Property *Copy(void) const;
|
||||||
virtual void Paste(const Property &from);
|
virtual void Paste(const Property &from);
|
||||||
|
virtual unsigned int getMemSize (void) const;
|
||||||
// get the transient path if the property is in a DocumentObject
|
|
||||||
std::string getDocTransientPath(void) const;
|
|
||||||
|
|
||||||
/** get a temp file name in the transient path of the document.
|
/** get a temp file name in the transient path of the document.
|
||||||
* Using this file for new Version of the file and set
|
* Using this file for new Version of the file and set
|
||||||
|
@ -107,8 +105,14 @@ public:
|
||||||
std::string getExchangeTempFile(void) const;
|
std::string getExchangeTempFile(void) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _cValue;
|
// get the transient path if the property is in a DocumentObject
|
||||||
std::string _BaseFileName;
|
std::string getDocTransientPath(void) const;
|
||||||
|
std::string getUniqueFileName(const std::string&, const std::string&) const;
|
||||||
|
void aboutToSetValue(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mutable std::string _cValue;
|
||||||
|
mutable std::string _BaseFileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ void PropertyVector::setPyObject(PyObject *value)
|
||||||
else if (PyInt_Check(item))
|
else if (PyInt_Check(item))
|
||||||
cVec.x = (float)PyInt_AsLong(item);
|
cVec.x = (float)PyInt_AsLong(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Not allowed type used in tuple (float expected)...");
|
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
|
||||||
// y
|
// y
|
||||||
item = PyTuple_GetItem(value,1);
|
item = PyTuple_GetItem(value,1);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
|
@ -125,7 +125,7 @@ void PropertyVector::setPyObject(PyObject *value)
|
||||||
else if (PyInt_Check(item))
|
else if (PyInt_Check(item))
|
||||||
cVec.y = (float)PyInt_AsLong(item);
|
cVec.y = (float)PyInt_AsLong(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Not allowed type used in tuple (float expected)...");
|
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
|
||||||
// z
|
// z
|
||||||
item = PyTuple_GetItem(value,2);
|
item = PyTuple_GetItem(value,2);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
|
@ -133,13 +133,13 @@ void PropertyVector::setPyObject(PyObject *value)
|
||||||
else if (PyInt_Check(item))
|
else if (PyInt_Check(item))
|
||||||
cVec.z = (float)PyInt_AsLong(item);
|
cVec.z = (float)PyInt_AsLong(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Not allowed type used in tuple (float expected)...");
|
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
|
||||||
setValue( cVec );
|
setValue( cVec );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'Vector' or tuple of three floats, not ");
|
std::string error = std::string("type must be 'Vector' or tuple of three floats, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ void PropertyVectorList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'Vector' or list of 'Vector', not ");
|
std::string error = std::string("type must be 'Vector' or list of 'Vector', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ void PropertyMatrix::setPyObject(PyObject *value)
|
||||||
else if (PyInt_Check(item))
|
else if (PyInt_Check(item))
|
||||||
cMatrix[x][y] = (double)PyInt_AsLong(item);
|
cMatrix[x][y] = (double)PyInt_AsLong(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Not allowed type used in matrix tuple (a number expected)...");
|
throw Base::TypeError("Not allowed type used in matrix tuple (a number expected)...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ void PropertyMatrix::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'Matrix' or tuple of 16 float or int, not ");
|
std::string error = std::string("type must be 'Matrix' or tuple of 16 float or int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ void PropertyPlacement::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'Matrix' or 'Placement', not ");
|
std::string error = std::string("type must be 'Matrix' or 'Placement', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ void PropertyLink::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'DocumentObject' or 'NoneType', not ");
|
std::string error = std::string("type must be 'DocumentObject' or 'NoneType', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ void PropertyLinkSub::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type of first element in tuple must be 'DocumentObject', not ");
|
std::string error = std::string("type of first element in tuple must be 'DocumentObject', not ");
|
||||||
error += tup[0].ptr()->ob_type->tp_name;
|
error += tup[0].ptr()->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(Py_None == value) {
|
else if(Py_None == value) {
|
||||||
|
@ -266,7 +266,7 @@ void PropertyLinkSub::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'DocumentObject', 'NoneType' or ('DocumentObject',['String',]) not ");
|
std::string error = std::string("type must be 'DocumentObject', 'NoneType' or ('DocumentObject',['String',]) not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ void PropertyLinkList::setPyObject(PyObject *value)
|
||||||
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
||||||
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
||||||
error += (*item)->ob_type->tp_name;
|
error += (*item)->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
||||||
|
@ -424,7 +424,7 @@ void PropertyLinkList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
|
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +609,7 @@ void PropertyLinkSubList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
|
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ std::string PropertyPythonObject::toString() const
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Warning("PropertyPythonObject::toString: %s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return repr;
|
return repr;
|
||||||
|
@ -139,7 +139,7 @@ void PropertyPythonObject::fromString(const std::string& repr)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Warning("PropertyPythonObject::fromString: %s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ void PropertyPythonObject::loadPickle(const std::string& str)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ void PropertyPythonObject::Save (Base::Writer &writer) const
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what());
|
e.ReportException();
|
||||||
}
|
}
|
||||||
|
|
||||||
saveObject(writer);
|
saveObject(writer);
|
||||||
|
@ -350,7 +350,7 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader)
|
||||||
}
|
}
|
||||||
catch (Py::Exception&) {
|
catch (Py::Exception&) {
|
||||||
Base::PyException e; // extract the Python error text
|
Base::PyException e; // extract the Python error text
|
||||||
Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what());
|
e.ReportException();
|
||||||
this->object = Py::None();
|
this->object = Py::None();
|
||||||
load_failed = true;
|
load_failed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ void PropertyInteger::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int, not ");
|
std::string error = std::string("type must be int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ void PropertyPath::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be str or unicode, not ");
|
std::string error = std::string("type must be str or unicode, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign the path
|
// assign the path
|
||||||
|
@ -472,7 +472,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
|
||||||
long i=0;
|
long i=0;
|
||||||
while(*(plEnums++) != NULL)i++;
|
while(*(plEnums++) != NULL)i++;
|
||||||
if (val < 0 || i <= val)
|
if (val < 0 || i <= val)
|
||||||
throw Py::ValueError("Out of range");
|
throw Base::ValueError("Out of range");
|
||||||
PropertyInteger::setValue(val);
|
PropertyInteger::setValue(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
|
||||||
if (_EnumArray && isPartOf(str))
|
if (_EnumArray && isPartOf(str))
|
||||||
setValue(PyString_AsString (value));
|
setValue(PyString_AsString (value));
|
||||||
else
|
else
|
||||||
throw Py::ValueError("not part of the enum");
|
throw Base::ValueError("not part of the enum");
|
||||||
}
|
}
|
||||||
else if (PyList_Check(value)) {
|
else if (PyList_Check(value)) {
|
||||||
Py_ssize_t nSize = PyList_Size(value);
|
Py_ssize_t nSize = PyList_Size(value);
|
||||||
|
@ -493,7 +493,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
|
||||||
if (!PyString_Check(item)) {
|
if (!PyString_Check(item)) {
|
||||||
std::string error = std::string("type in list must be str, not ");
|
std::string error = std::string("type in list must be str, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
values[i] = PyString_AsString(item);
|
values[i] = PyString_AsString(item);
|
||||||
}
|
}
|
||||||
|
@ -505,10 +505,33 @@ void PropertyEnumeration::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int or str, not ");
|
std::string error = std::string("type must be int or str, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Property *PropertyEnumeration::Copy(void) const
|
||||||
|
{
|
||||||
|
PropertyEnumeration *p= new PropertyEnumeration();
|
||||||
|
p->_lValue = _lValue;
|
||||||
|
if (_CustomEnum) {
|
||||||
|
p->_CustomEnum = true;
|
||||||
|
p->setEnumVector(getEnumVector());
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertyEnumeration::Paste(const Property &from)
|
||||||
|
{
|
||||||
|
aboutToSetValue();
|
||||||
|
const PropertyEnumeration& prop = dynamic_cast<const PropertyEnumeration&>(from);
|
||||||
|
_lValue = prop._lValue;
|
||||||
|
if (prop._CustomEnum) {
|
||||||
|
this->_CustomEnum = true;
|
||||||
|
this->setEnumVector(prop.getEnumVector());
|
||||||
|
}
|
||||||
|
hasSetValue();
|
||||||
|
}
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
// PropertyIntegerConstraint
|
// PropertyIntegerConstraint
|
||||||
|
@ -559,7 +582,7 @@ void PropertyIntegerConstraint::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int, not ");
|
std::string error = std::string("type must be int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +677,7 @@ void PropertyIntegerList::setPyObject(PyObject *value)
|
||||||
if (!PyInt_Check(item)) {
|
if (!PyInt_Check(item)) {
|
||||||
std::string error = std::string("type in list must be int, not ");
|
std::string error = std::string("type in list must be int, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
values[i] = PyInt_AsLong(item);
|
values[i] = PyInt_AsLong(item);
|
||||||
}
|
}
|
||||||
|
@ -667,7 +690,7 @@ void PropertyIntegerList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int or list of int, not ");
|
std::string error = std::string("type must be int or list of int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +805,7 @@ void PropertyIntegerSet::setPyObject(PyObject *value)
|
||||||
if (!PyInt_Check(item)) {
|
if (!PyInt_Check(item)) {
|
||||||
std::string error = std::string("type in list must be int, not ");
|
std::string error = std::string("type in list must be int, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
values.insert(PyInt_AsLong(item));
|
values.insert(PyInt_AsLong(item));
|
||||||
}
|
}
|
||||||
|
@ -795,7 +818,7 @@ void PropertyIntegerSet::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int or list of int, not ");
|
std::string error = std::string("type must be int or list of int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,7 +845,7 @@ void PropertyIntegerSet::Restore(Base::XMLReader &reader)
|
||||||
values.insert(reader.getAttributeAsInteger("v"));
|
values.insert(reader.getAttributeAsInteger("v"));
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.readEndElement("IntegerList");
|
reader.readEndElement("IntegerSet");
|
||||||
|
|
||||||
//assignment
|
//assignment
|
||||||
setValues(values);
|
setValues(values);
|
||||||
|
@ -905,7 +928,7 @@ void PropertyFloat::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be float or int, not ");
|
std::string error = std::string("type must be float or int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,7 +1022,7 @@ void PropertyFloatConstraint::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be float, not ");
|
std::string error = std::string("type must be float, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,7 +1095,7 @@ void PropertyFloatList::setPyObject(PyObject *value)
|
||||||
if (!PyFloat_Check(item)) {
|
if (!PyFloat_Check(item)) {
|
||||||
std::string error = std::string("type in list must be float, not ");
|
std::string error = std::string("type in list must be float, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
values[i] = (float) PyFloat_AsDouble(item);
|
values[i] = (float) PyFloat_AsDouble(item);
|
||||||
|
@ -1086,7 +1109,7 @@ void PropertyFloatList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be float or list of float, not ");
|
std::string error = std::string("type must be float or list of float, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,7 +1240,7 @@ void PropertyString::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be str or unicode, not ");
|
std::string error = std::string("type must be str or unicode, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign the string
|
// assign the string
|
||||||
|
@ -1322,11 +1345,18 @@ void PropertyUUID::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be a str, not ");
|
std::string error = std::string("type must be a str, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
// assign the string
|
// assign the string
|
||||||
setValue(string);
|
Base::Uuid uid;
|
||||||
|
uid.setValue(string);
|
||||||
|
setValue(uid);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
throw Base::RuntimeError(e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertyUUID::Save (Base::Writer &writer) const
|
void PropertyUUID::Save (Base::Writer &writer) const
|
||||||
|
@ -1465,7 +1495,7 @@ void PropertyStringList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type in list must be str or unicode, not ");
|
std::string error = std::string("type in list must be str or unicode, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,7 +1507,7 @@ void PropertyStringList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be str or list of str, not ");
|
std::string error = std::string("type must be str or list of str, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1625,7 +1655,7 @@ void PropertyMap::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type of the key need to be a string, not");
|
std::string error = std::string("type of the key need to be a string, not");
|
||||||
error += key->ob_type->tp_name;
|
error += key->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check on the item:
|
// check on the item:
|
||||||
|
@ -1641,7 +1671,7 @@ void PropertyMap::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type in list must be string or unicode, not ");
|
std::string error = std::string("type in list must be string or unicode, not ");
|
||||||
error += item->ob_type->tp_name;
|
error += item->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1650,7 +1680,7 @@ void PropertyMap::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be a dict object");
|
std::string error = std::string("type must be a dict object");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1764,7 +1794,7 @@ void PropertyBool::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be bool, not ");
|
std::string error = std::string("type must be bool, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1876,17 +1906,17 @@ void PropertyColor::setPyObject(PyObject *value)
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.r = (float)PyFloat_AsDouble(item);
|
cCol.r = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
item = PyTuple_GetItem(value,1);
|
item = PyTuple_GetItem(value,1);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.g = (float)PyFloat_AsDouble(item);
|
cCol.g = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
item = PyTuple_GetItem(value,2);
|
item = PyTuple_GetItem(value,2);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.b = (float)PyFloat_AsDouble(item);
|
cCol.b = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
}
|
}
|
||||||
else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) {
|
else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) {
|
||||||
PyObject* item;
|
PyObject* item;
|
||||||
|
@ -1894,22 +1924,22 @@ void PropertyColor::setPyObject(PyObject *value)
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.r = (float)PyFloat_AsDouble(item);
|
cCol.r = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
item = PyTuple_GetItem(value,1);
|
item = PyTuple_GetItem(value,1);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.g = (float)PyFloat_AsDouble(item);
|
cCol.g = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
item = PyTuple_GetItem(value,2);
|
item = PyTuple_GetItem(value,2);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.b = (float)PyFloat_AsDouble(item);
|
cCol.b = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
item = PyTuple_GetItem(value,3);
|
item = PyTuple_GetItem(value,3);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
cCol.a = (float)PyFloat_AsDouble(item);
|
cCol.a = (float)PyFloat_AsDouble(item);
|
||||||
else
|
else
|
||||||
throw Base::Exception("Type in tuple must be float");
|
throw Base::TypeError("Type in tuple must be float");
|
||||||
}
|
}
|
||||||
else if (PyLong_Check(value)) {
|
else if (PyLong_Check(value)) {
|
||||||
cCol.setPackedValue(PyLong_AsUnsignedLong(value));
|
cCol.setPackedValue(PyLong_AsUnsignedLong(value));
|
||||||
|
@ -1917,7 +1947,7 @@ void PropertyColor::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be int or tuple of float, not ");
|
std::string error = std::string("type must be int or tuple of float, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue( cCol );
|
setValue( cCol );
|
||||||
|
@ -2050,7 +2080,7 @@ void PropertyColorList::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("not allowed type, ");
|
std::string error = std::string("not allowed type, ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2201,7 +2231,7 @@ void PropertyMaterial::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be 'Material', not ");
|
std::string error = std::string("type must be 'Material', not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,9 @@ public:
|
||||||
virtual void Save (Base::Writer &writer) const;
|
virtual void Save (Base::Writer &writer) const;
|
||||||
virtual void Restore(Base::XMLReader &reader);
|
virtual void Restore(Base::XMLReader &reader);
|
||||||
|
|
||||||
|
virtual Property *Copy(void) const;
|
||||||
|
virtual void Paste(const Property &from);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _CustomEnum;
|
bool _CustomEnum;
|
||||||
const char** _EnumArray;
|
const char** _EnumArray;
|
||||||
|
|
|
@ -102,11 +102,11 @@ void PropertyLength::setPyObject(PyObject *value)
|
||||||
else {
|
else {
|
||||||
std::string error = std::string("type must be float or int, not ");
|
std::string error = std::string("type must be float or int, not ");
|
||||||
error += value->ob_type->tp_name;
|
error += value->ob_type->tp_name;
|
||||||
throw Py::TypeError(error);
|
throw Base::TypeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val < 0.0f)
|
if (val < 0.0f)
|
||||||
throw Py::ValueError("value must be nonnegative");
|
throw Base::ValueError("value must be nonnegative");
|
||||||
|
|
||||||
setValue(val);
|
setValue(val);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
<UserDocu>Returns all descentences</UserDocu>
|
<UserDocu>Returns all descentences</UserDocu>
|
||||||
</Documentation>
|
</Documentation>
|
||||||
</Methode>
|
</Methode>
|
||||||
<Attribute Name="Type" ReadOnly="true">
|
<Attribute Name="TypeId" ReadOnly="true">
|
||||||
<Documentation>
|
<Documentation>
|
||||||
<UserDocu>Is the type of the FreeCAD object with module domain</UserDocu>
|
<UserDocu>Is the type of the FreeCAD object with module domain</UserDocu>
|
||||||
</Documentation>
|
</Documentation>
|
||||||
<Parameter Name="Type" Type="String" />
|
<Parameter Name="TypeId" Type="String" />
|
||||||
</Attribute>
|
</Attribute>
|
||||||
<Attribute Name="Module" ReadOnly="true">
|
<Attribute Name="Module" ReadOnly="true">
|
||||||
<Documentation>
|
<Documentation>
|
||||||
|
|
|
@ -68,7 +68,7 @@ PyObject* BaseClassPy::getAllDerivedFrom(PyObject *args)
|
||||||
return Py::new_reference_to(res);
|
return Py::new_reference_to(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Py::String BaseClassPy::getType(void) const
|
Py::String BaseClassPy::getTypeId(void) const
|
||||||
{
|
{
|
||||||
return Py::String(std::string(getBaseClassPtr()->getTypeId().getName()));
|
return Py::String(std::string(getBaseClassPtr()->getTypeId().getName()));
|
||||||
}
|
}
|
||||||
|
@ -78,8 +78,15 @@ Py::Int BaseClassPy::getModule(void) const
|
||||||
return Py::Int();
|
return Py::Int();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *BaseClassPy::getCustomAttributes(const char* /*attr*/) const
|
PyObject *BaseClassPy::getCustomAttributes(const char* attr) const
|
||||||
{
|
{
|
||||||
|
// this attribute is marked 'deprecated' but to keep old code working we
|
||||||
|
// handle it here. In a future version this will be removed.
|
||||||
|
if (strcmp(attr, "Type") == 0) {
|
||||||
|
PyErr_SetString(PyExc_DeprecationWarning, "Use 'TypeId' instead");
|
||||||
|
PyErr_Print();
|
||||||
|
return Py::new_reference_to(Py::String(std::string(getBaseClassPtr()->getTypeId().getName())));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,74 @@ ProgramInformation::ProgramInformation(const ProgramInformation &inst)
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
TypeError::TypeError(const char * sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeError::TypeError(const std::string& sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeError::TypeError(const TypeError &inst)
|
||||||
|
: Exception(inst)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
ValueError::ValueError(const char * sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueError::ValueError(const std::string& sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueError::ValueError(const ValueError &inst)
|
||||||
|
: Exception(inst)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
AttributeError::AttributeError(const char * sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeError::AttributeError(const std::string& sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeError::AttributeError(const AttributeError &inst)
|
||||||
|
: Exception(inst)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
RuntimeError::RuntimeError(const char * sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeError::RuntimeError(const std::string& sMessage)
|
||||||
|
: Exception(sMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeError::RuntimeError(const RuntimeError &inst)
|
||||||
|
: Exception(inst)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__GNUC__) && defined (FC_OS_LINUX)
|
#if defined(__GNUC__) && defined (FC_OS_LINUX)
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
Exception &operator=(const Exception &inst);
|
Exception &operator=(const Exception &inst);
|
||||||
virtual const char* what(void) const throw();
|
virtual const char* what(void) const throw();
|
||||||
void ReportException (void) const;
|
virtual void ReportException (void) const;
|
||||||
inline void setMessage(const char * sMessage);
|
inline void setMessage(const char * sMessage);
|
||||||
inline void setMessage(const std::string& sMessage);
|
inline void setMessage(const std::string& sMessage);
|
||||||
|
|
||||||
|
@ -206,6 +206,70 @@ public:
|
||||||
virtual ~ProgramInformation() throw() {}
|
virtual ~ProgramInformation() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TypeError can be used to indicate the usage of a wrong type.
|
||||||
|
* @author Werner Mayer
|
||||||
|
*/
|
||||||
|
class BaseExport TypeError : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Construction
|
||||||
|
TypeError(const char * sMessage);
|
||||||
|
TypeError(const std::string& sMessage);
|
||||||
|
/// Construction
|
||||||
|
TypeError(const TypeError &inst);
|
||||||
|
/// Destruction
|
||||||
|
virtual ~TypeError() throw() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ValueError can be used to indicate the usage of a wrong value.
|
||||||
|
* @author Werner Mayer
|
||||||
|
*/
|
||||||
|
class BaseExport ValueError : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Construction
|
||||||
|
ValueError(const char * sMessage);
|
||||||
|
ValueError(const std::string& sMessage);
|
||||||
|
/// Construction
|
||||||
|
ValueError(const ValueError &inst);
|
||||||
|
/// Destruction
|
||||||
|
virtual ~ValueError() throw() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AttributeError can be used to indicate the usage of a wrong value.
|
||||||
|
* @author Werner Mayer
|
||||||
|
*/
|
||||||
|
class BaseExport AttributeError : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Construction
|
||||||
|
AttributeError(const char * sMessage);
|
||||||
|
AttributeError(const std::string& sMessage);
|
||||||
|
/// Construction
|
||||||
|
AttributeError(const AttributeError &inst);
|
||||||
|
/// Destruction
|
||||||
|
virtual ~AttributeError() throw() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RuntimeError can be used to indicate an unknown exception at runtime.
|
||||||
|
* @author Werner Mayer
|
||||||
|
*/
|
||||||
|
class BaseExport RuntimeError : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Construction
|
||||||
|
RuntimeError(const char * sMessage);
|
||||||
|
RuntimeError(const std::string& sMessage);
|
||||||
|
/// Construction
|
||||||
|
RuntimeError(const RuntimeError &inst);
|
||||||
|
/// Destruction
|
||||||
|
virtual ~RuntimeError() throw() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
inline void Exception::setMessage(const char * sMessage)
|
inline void Exception::setMessage(const char * sMessage)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "PreCompiled.h"
|
#include "PreCompiled.h"
|
||||||
|
|
||||||
#ifndef _PreComp_
|
#ifndef _PreComp_
|
||||||
|
# include <algorithm>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
# include <cstdio>
|
# include <cstdio>
|
||||||
# include <cstdlib>
|
# include <cstdlib>
|
||||||
|
@ -51,10 +52,20 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#define new DEBUG_CLIENTBLOCK
|
|
||||||
|
|
||||||
using namespace Base;
|
using namespace Base;
|
||||||
|
|
||||||
|
#ifndef R_OK
|
||||||
|
#define R_OK 4 /* Test for read permission */
|
||||||
|
#endif
|
||||||
|
#ifndef W_OK
|
||||||
|
#define W_OK 2 /* Test for write permission */
|
||||||
|
#endif
|
||||||
|
#ifndef X_OK
|
||||||
|
#define X_OK 1 /* Test for execute permission */
|
||||||
|
#endif
|
||||||
|
#ifndef F_OK
|
||||||
|
#define F_OK 0 /* Test for existence */
|
||||||
|
#endif
|
||||||
|
|
||||||
//**********************************************************************************
|
//**********************************************************************************
|
||||||
// helper
|
// helper
|
||||||
|
@ -188,22 +199,13 @@ std::string FileInfo::getTempFileName(const char* FileName, const char* Path)
|
||||||
|
|
||||||
void FileInfo::setFile(const char* name)
|
void FileInfo::setFile(const char* name)
|
||||||
{
|
{
|
||||||
std::string result;
|
if (!name) {
|
||||||
const char *It=name;
|
FileName.clear();
|
||||||
|
return;
|
||||||
while(*It != '\0') {
|
|
||||||
switch(*It)
|
|
||||||
{
|
|
||||||
case '\\':
|
|
||||||
result += "/";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result += *It;
|
|
||||||
}
|
|
||||||
It++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileName = result;
|
FileName = name;
|
||||||
|
std::replace(FileName.begin(), FileName.end(), '\\', '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FileInfo::filePath () const
|
std::string FileInfo::filePath () const
|
||||||
|
@ -271,9 +273,9 @@ bool FileInfo::exists () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),0) == 0;
|
return _waccess(wstr.c_str(),F_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),0) == 0;
|
return access(FileName.c_str(),F_OK) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,9 +283,9 @@ bool FileInfo::isReadable () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),4) == 0;
|
return _waccess(wstr.c_str(),R_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),4) == 0;
|
return access(FileName.c_str(),R_OK) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,9 +293,29 @@ bool FileInfo::isWritable () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),2) == 0;
|
return _waccess(wstr.c_str(),W_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),2) == 0;
|
return access(FileName.c_str(),W_OK) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInfo::setPermissions (Permissions perms)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
if (perms & FileInfo::ReadOnly)
|
||||||
|
mode |= S_IREAD;
|
||||||
|
if (perms & FileInfo::WriteOnly)
|
||||||
|
mode |= S_IWRITE;
|
||||||
|
|
||||||
|
if (mode == 0) // bad argument
|
||||||
|
return false;
|
||||||
|
#if defined (FC_OS_WIN32)
|
||||||
|
std::wstring wstr = toStdWString();
|
||||||
|
return _wchmod(wstr.c_str(),mode) == 0;
|
||||||
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
|
return chmod(FileName.c_str(),mode) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +450,6 @@ bool FileInfo::renameFile(const char* NewName)
|
||||||
#else
|
#else
|
||||||
# error "FileInfo::renameFile() not implemented for this platform!"
|
# error "FileInfo::renameFile() not implemented for this platform!"
|
||||||
#endif
|
#endif
|
||||||
setFile(NewName);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -482,13 +503,18 @@ bool FileInfo::deleteDirectoryRecursive(void) const
|
||||||
std::vector<Base::FileInfo> List = getDirectoryContent();
|
std::vector<Base::FileInfo> List = getDirectoryContent();
|
||||||
|
|
||||||
for (std::vector<Base::FileInfo>::iterator It = List.begin();It!=List.end();++It) {
|
for (std::vector<Base::FileInfo>::iterator It = List.begin();It!=List.end();++It) {
|
||||||
if (It->isDir())
|
if (It->isDir()) {
|
||||||
|
It->setPermissions(FileInfo::ReadWrite);
|
||||||
It->deleteDirectoryRecursive();
|
It->deleteDirectoryRecursive();
|
||||||
else if(It->isFile())
|
}
|
||||||
|
else if (It->isFile()) {
|
||||||
|
It->setPermissions(FileInfo::ReadWrite);
|
||||||
It->deleteFile();
|
It->deleteFile();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!");
|
Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return deleteDirectory();
|
return deleteDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,12 @@ namespace Base
|
||||||
class BaseExport FileInfo
|
class BaseExport FileInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum Permissions {
|
||||||
|
WriteOnly = 0x01,
|
||||||
|
ReadOnly = 0x02,
|
||||||
|
ReadWrite = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
/// Constrction
|
/// Constrction
|
||||||
FileInfo (const char* _FileName="");
|
FileInfo (const char* _FileName="");
|
||||||
FileInfo (const std::string &_FileName);
|
FileInfo (const std::string &_FileName);
|
||||||
|
@ -89,6 +95,8 @@ public:
|
||||||
bool isReadable () const;
|
bool isReadable () const;
|
||||||
/// Checks if the file exist and is writable
|
/// Checks if the file exist and is writable
|
||||||
bool isWritable () const;
|
bool isWritable () const;
|
||||||
|
/// Tries to set the file permisson
|
||||||
|
bool setPermissions (Permissions);
|
||||||
/// Checks if it is a file (not a direrctory)
|
/// Checks if it is a file (not a direrctory)
|
||||||
bool isFile () const;
|
bool isFile () const;
|
||||||
/// Checks if it is a directory (not a file)
|
/// Checks if it is a directory (not a file)
|
||||||
|
@ -109,7 +117,7 @@ public:
|
||||||
std::vector<Base::FileInfo> getDirectoryContent(void) const;
|
std::vector<Base::FileInfo> getDirectoryContent(void) const;
|
||||||
/// Delete an empty directory
|
/// Delete an empty directory
|
||||||
bool deleteDirectory(void) const;
|
bool deleteDirectory(void) const;
|
||||||
/// Delete a directory and all its content
|
/// Delete a directory and all its content.
|
||||||
bool deleteDirectoryRecursive(void) const;
|
bool deleteDirectoryRecursive(void) const;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,18 @@ PyException::PyException(void)
|
||||||
|
|
||||||
|
|
||||||
_stackTrace = PP_last_error_trace; /* exception traceback text */
|
_stackTrace = PP_last_error_trace; /* exception traceback text */
|
||||||
|
}
|
||||||
|
|
||||||
|
PyException::~PyException() throw()
|
||||||
|
{
|
||||||
|
PyGILStateLocker locker;
|
||||||
PyErr_Clear(); // must be called to keep Python interpreter in a valid state (Werner)
|
PyErr_Clear(); // must be called to keep Python interpreter in a valid state (Werner)
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyException::ReportException (void) const
|
||||||
|
{
|
||||||
|
Base::Console().Error("%s%s: %s\n",
|
||||||
|
_stackTrace.c_str(), _errorType.c_str(), what());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
|
|
|
@ -54,11 +54,12 @@ class BaseExport PyException : public Exception
|
||||||
public:
|
public:
|
||||||
/// constructor does the whole job
|
/// constructor does the whole job
|
||||||
PyException(void);
|
PyException(void);
|
||||||
~PyException() throw() {}
|
~PyException() throw();
|
||||||
|
|
||||||
/// this function returns the stack trace
|
/// this function returns the stack trace
|
||||||
const std::string &getStackTrace(void) const {return _stackTrace;}
|
const std::string &getStackTrace(void) const {return _stackTrace;}
|
||||||
const std::string &getErrorType(void) const {return _errorType;}
|
const std::string &getErrorType(void) const {return _errorType;}
|
||||||
|
void ReportException (void) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _stackTrace;
|
std::string _stackTrace;
|
||||||
|
|
|
@ -38,9 +38,16 @@ using namespace Base;
|
||||||
std::string RotationPy::representation(void) const
|
std::string RotationPy::representation(void) const
|
||||||
{
|
{
|
||||||
RotationPy::PointerType ptr = reinterpret_cast<RotationPy::PointerType>(_pcTwinPointer);
|
RotationPy::PointerType ptr = reinterpret_cast<RotationPy::PointerType>(_pcTwinPointer);
|
||||||
|
Py::Float q0(ptr->getValue()[0]);
|
||||||
|
Py::Float q1(ptr->getValue()[1]);
|
||||||
|
Py::Float q2(ptr->getValue()[2]);
|
||||||
|
Py::Float q3(ptr->getValue()[3]);
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "Quaternion (";
|
str << "Rotation (";
|
||||||
str << ptr->getValue()[0] << ","<< ptr->getValue()[1] << "," << ptr->getValue()[2] << "," << ptr->getValue()[3];
|
str << (std::string)q0.repr() << ", "
|
||||||
|
<< (std::string)q1.repr() << ", "
|
||||||
|
<< (std::string)q2.repr() << ", "
|
||||||
|
<< (std::string)q3.repr();
|
||||||
str << ")";
|
str << ")";
|
||||||
|
|
||||||
return str.str();
|
return str.str();
|
||||||
|
|
|
@ -40,9 +40,12 @@ using namespace Base;
|
||||||
std::string VectorPy::representation(void) const
|
std::string VectorPy::representation(void) const
|
||||||
{
|
{
|
||||||
VectorPy::PointerType ptr = reinterpret_cast<VectorPy::PointerType>(_pcTwinPointer);
|
VectorPy::PointerType ptr = reinterpret_cast<VectorPy::PointerType>(_pcTwinPointer);
|
||||||
|
Py::Float x(ptr->x);
|
||||||
|
Py::Float y(ptr->y);
|
||||||
|
Py::Float z(ptr->z);
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "Vector (";
|
str << "Vector (";
|
||||||
str << ptr->x << ", "<< ptr->y << ", "<< ptr->z;
|
str << (std::string)x.repr() << ", "<< (std::string)y.repr() << ", "<< (std::string)z.repr();
|
||||||
str << ")";
|
str << ")";
|
||||||
|
|
||||||
return str.str();
|
return str.str();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
// Version Number
|
// Version Number
|
||||||
#define FCVersionMajor "0"
|
#define FCVersionMajor "0"
|
||||||
#define FCVersionMinor "13"
|
#define FCVersionMinor "14"
|
||||||
#define FCVersionName "Vulcan"
|
#define FCVersionName "Vulcan"
|
||||||
// test: $Format:Hash (%H), Date: %ci$
|
// test: $Format:Hash (%H), Date: %ci$
|
||||||
#define FCRevision "$WCREV$" //Highest committed revision number
|
#define FCRevision "$WCREV$" //Highest committed revision number
|
||||||
|
|
|
@ -41,8 +41,11 @@
|
||||||
# include <QGLFramebufferObject>
|
# include <QGLFramebufferObject>
|
||||||
#endif
|
#endif
|
||||||
# include <QSessionManager>
|
# include <QSessionManager>
|
||||||
|
# include <QTextStream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/interprocess/sync/file_lock.hpp>
|
||||||
|
|
||||||
|
|
||||||
// FreeCAD Base header
|
// FreeCAD Base header
|
||||||
#include <Base/Console.h>
|
#include <Base/Console.h>
|
||||||
|
@ -336,6 +339,18 @@ Application::Application(bool GUIenabled)
|
||||||
("User parameter:BaseApp/Preferences/Units");
|
("User parameter:BaseApp/Preferences/Units");
|
||||||
Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals()));
|
Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals()));
|
||||||
|
|
||||||
|
// Check for the symbols for group separator and deciaml point. They must be different otherwise
|
||||||
|
// Qt doesn't work properly.
|
||||||
|
#if defined(Q_OS_WIN32)
|
||||||
|
if (QLocale::system().groupSeparator() == QLocale::system().decimalPoint()) {
|
||||||
|
QMessageBox::critical(0, QLatin1String("Invalid system settings"),
|
||||||
|
QLatin1String("Your system uses the same symbol for decimal point and group separator.\n\n"
|
||||||
|
"This causes serious problems and makes the application fail to work properly.\n"
|
||||||
|
"Go to the system configuration panel of the OS and fix this issue, please."));
|
||||||
|
throw Base::Exception("Invalid system settings");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// setting up Python binding
|
// setting up Python binding
|
||||||
Base::PyGILStateLocker lock;
|
Base::PyGILStateLocker lock;
|
||||||
PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods,
|
PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods,
|
||||||
|
@ -1739,9 +1754,24 @@ void Application::runApplication(void)
|
||||||
Base::Console().Log("Init: Entering event loop\n");
|
Base::Console().Log("Init: Entering event loop\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
std::stringstream s;
|
||||||
|
s << Base::FileInfo::getTempPath() << App::GetApplication().getExecutableName()
|
||||||
|
<< "_" << QCoreApplication::applicationPid() << ".lock";
|
||||||
|
// open a lock file with the PID
|
||||||
|
Base::FileInfo fi(s.str());
|
||||||
|
Base::ofstream lock(fi);
|
||||||
|
boost::interprocess::file_lock flock(s.str().c_str());
|
||||||
|
flock.lock();
|
||||||
|
|
||||||
int ret = mainApp.exec();
|
int ret = mainApp.exec();
|
||||||
if (ret == systemExit)
|
if (ret == systemExit)
|
||||||
throw Base::SystemExitException();
|
throw Base::SystemExitException();
|
||||||
|
|
||||||
|
// close the lock file, in case of a crash we can see the existing lock file
|
||||||
|
// on the next restart and try to repair the documents, if needed.
|
||||||
|
flock.unlock();
|
||||||
|
lock.close();
|
||||||
|
fi.deleteFile();
|
||||||
}
|
}
|
||||||
catch (const Base::SystemExitException&) {
|
catch (const Base::SystemExitException&) {
|
||||||
Base::Console().Message("System exit\n");
|
Base::Console().Message("System exit\n");
|
||||||
|
@ -1756,3 +1786,66 @@ void Application::runApplication(void)
|
||||||
|
|
||||||
Base::Console().Log("Finish: Event loop left\n");
|
Base::Console().Log("Finish: Event loop left\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::checkForPreviousCrashes()
|
||||||
|
{
|
||||||
|
QDir tmp = QDir::temp();
|
||||||
|
tmp.setNameFilters(QStringList() << QString::fromAscii("*.lock"));
|
||||||
|
tmp.setFilter(QDir::Files);
|
||||||
|
|
||||||
|
QList<QFileInfo> restoreDocFiles;
|
||||||
|
QString exeName = QString::fromAscii(App::GetApplication().getExecutableName());
|
||||||
|
QList<QFileInfo> locks = tmp.entryInfoList();
|
||||||
|
for (QList<QFileInfo>::iterator it = locks.begin(); it != locks.end(); ++it) {
|
||||||
|
QString bn = it->baseName();
|
||||||
|
// ignore the lock file for this instance
|
||||||
|
QString pid = QString::number(QCoreApplication::applicationPid());
|
||||||
|
if (bn.startsWith(exeName) && bn.indexOf(pid) < 0) {
|
||||||
|
QString fn = it->absoluteFilePath();
|
||||||
|
boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit());
|
||||||
|
if (flock.try_lock()) {
|
||||||
|
// OK, this file is a leftover from a previous crash
|
||||||
|
QString crashed_pid = bn.mid(exeName.length()+1);
|
||||||
|
// search for transient directories with this PID
|
||||||
|
QString filter;
|
||||||
|
QTextStream str(&filter);
|
||||||
|
str << exeName << "_Doc_*_" << crashed_pid;
|
||||||
|
tmp.setNameFilters(QStringList() << filter);
|
||||||
|
tmp.setFilter(QDir::Dirs);
|
||||||
|
QList<QFileInfo> dirs = tmp.entryInfoList();
|
||||||
|
if (dirs.isEmpty()) {
|
||||||
|
// delete the lock file immediately if not transient directories are related
|
||||||
|
tmp.remove(fn);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int countDeletedDocs = 0;
|
||||||
|
for (QList<QFileInfo>::iterator it = dirs.begin(); it != dirs.end(); ++it) {
|
||||||
|
QDir doc_dir(it->absoluteFilePath());
|
||||||
|
doc_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries);
|
||||||
|
uint entries = doc_dir.entryList().count();
|
||||||
|
if (entries == 0) {
|
||||||
|
// in this case we can delete the transient directory because
|
||||||
|
// we cannot do anything
|
||||||
|
if (tmp.rmdir(it->filePath()))
|
||||||
|
countDeletedDocs++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// store the transient directory in case it's not empty
|
||||||
|
restoreDocFiles << *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// all directories corresponding to the lock file have been deleted
|
||||||
|
// so delete the lock file, too
|
||||||
|
if (countDeletedDocs == dirs.size()) {
|
||||||
|
tmp.remove(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!restoreDocFiles.isEmpty()) {
|
||||||
|
//TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ public:
|
||||||
|
|
||||||
/// true when the application shuting down
|
/// true when the application shuting down
|
||||||
bool isClosing(void);
|
bool isClosing(void);
|
||||||
|
void checkForPreviousCrashes();
|
||||||
|
|
||||||
/** @name workbench handling */
|
/** @name workbench handling */
|
||||||
//@{
|
//@{
|
||||||
|
@ -210,6 +211,7 @@ public:
|
||||||
|
|
||||||
PYFUNCDEF_S(sSendActiveView);
|
PYFUNCDEF_S(sSendActiveView);
|
||||||
|
|
||||||
|
PYFUNCDEF_S(sGetMainWindow);
|
||||||
PYFUNCDEF_S(sUpdateGui);
|
PYFUNCDEF_S(sUpdateGui);
|
||||||
PYFUNCDEF_S(sUpdateLocale);
|
PYFUNCDEF_S(sUpdateLocale);
|
||||||
PYFUNCDEF_S(sGetLocale);
|
PYFUNCDEF_S(sGetLocale);
|
||||||
|
|
|
@ -83,6 +83,9 @@ PyMethodDef Application::Methods[] = {
|
||||||
{"addIcon", (PyCFunction) Application::sAddIcon, 1,
|
{"addIcon", (PyCFunction) Application::sAddIcon, 1,
|
||||||
"addIcon(string, string or list) -> None\n\n"
|
"addIcon(string, string or list) -> None\n\n"
|
||||||
"Add an icon as file name or in XPM format to the system"},
|
"Add an icon as file name or in XPM format to the system"},
|
||||||
|
{"getMainWindow", (PyCFunction) Application::sGetMainWindow, 1,
|
||||||
|
"getMainWindow() -> QMainWindow\n\n"
|
||||||
|
"Return the main window instance"},
|
||||||
{"updateGui", (PyCFunction) Application::sUpdateGui, 1,
|
{"updateGui", (PyCFunction) Application::sUpdateGui, 1,
|
||||||
"updateGui() -> None\n\n"
|
"updateGui() -> None\n\n"
|
||||||
"Update the main window and all its windows"},
|
"Update the main window and all its windows"},
|
||||||
|
@ -418,6 +421,22 @@ PyObject* Application::sSendActiveView(PyObject * /*self*/, PyObject *args,PyObj
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* Application::sGetMainWindow(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PythonWrapper wrap;
|
||||||
|
wrap.loadCoreModule();
|
||||||
|
wrap.loadGuiModule();
|
||||||
|
try {
|
||||||
|
return Py::new_reference_to(wrap.fromQWidget(Gui::getMainWindow(), "QMainWindow"));
|
||||||
|
}
|
||||||
|
catch (const Py::Exception&) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PyObject* Application::sUpdateGui(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
|
PyObject* Application::sUpdateGui(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
|
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
|
||||||
|
|
|
@ -84,7 +84,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
|
||||||
// up the inheritance hierarchy.
|
// up the inheritance hierarchy.
|
||||||
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
|
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
|
||||||
// Switch off viewing mode (Bug #0000911)
|
// Switch off viewing mode (Bug #0000911)
|
||||||
if (!this->isSeekMode() && this->isViewing())
|
if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
|
||||||
this->setViewing(false); // by default disable viewing mode to render the scene
|
this->setViewing(false); // by default disable viewing mode to render the scene
|
||||||
|
|
||||||
const SoType type(ev->getTypeId());
|
const SoType type(ev->getTypeId());
|
||||||
|
|
|
@ -86,7 +86,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
|
||||||
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
|
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
|
||||||
#else
|
#else
|
||||||
// Switch off viewing mode (Bug #0000911)
|
// Switch off viewing mode (Bug #0000911)
|
||||||
if (!this->isSeekMode() && this->isViewing())
|
if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
|
||||||
this->setViewing(false); // by default disable viewing mode to render the scene
|
this->setViewing(false); // by default disable viewing mode to render the scene
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_definitions(-DFCGui -DQIIS_MAKEDLL)
|
add_definitions(-DFCGui -DQIIS_MAKEDLL)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
if (FREECAD_USE_3DCONNEXION)
|
if (FREECAD_USE_3DCONNEXION)
|
||||||
add_definitions(-D_USE_3DCONNEXION_SDK)
|
add_definitions(-D_USE_3DCONNEXION_SDK)
|
||||||
endif(FREECAD_USE_3DCONNEXION)
|
endif(FREECAD_USE_3DCONNEXION)
|
||||||
|
@ -59,6 +60,30 @@ IF(SPNAV_FOUND)
|
||||||
)
|
)
|
||||||
ENDIF(SPNAV_FOUND)
|
ENDIF(SPNAV_FOUND)
|
||||||
|
|
||||||
|
if(SHIBOKEN_INCLUDE_DIR)
|
||||||
|
add_definitions(-DHAVE_SHIBOKEN)
|
||||||
|
include_directories(
|
||||||
|
${SHIBOKEN_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
set(FreeCADGui_LIBS
|
||||||
|
${FreeCADGui_LIBS}
|
||||||
|
${SHIBOKEN_LIBRARY}
|
||||||
|
)
|
||||||
|
endif(SHIBOKEN_INCLUDE_DIR)
|
||||||
|
|
||||||
|
if(PYSIDE_INCLUDE_DIR)
|
||||||
|
add_definitions(-DHAVE_PYSIDE)
|
||||||
|
include_directories(
|
||||||
|
${PYSIDE_INCLUDE_DIR}
|
||||||
|
${PYSIDE_INCLUDE_DIR}/QtCore
|
||||||
|
${PYSIDE_INCLUDE_DIR}/QtGui
|
||||||
|
)
|
||||||
|
set(FreeCADGui_LIBS
|
||||||
|
${FreeCADGui_LIBS}
|
||||||
|
${PYSIDE_LIBRARY}
|
||||||
|
)
|
||||||
|
endif(PYSIDE_INCLUDE_DIR)
|
||||||
|
|
||||||
generate_from_xml(DocumentPy)
|
generate_from_xml(DocumentPy)
|
||||||
generate_from_xml(PythonWorkbenchPy)
|
generate_from_xml(PythonWorkbenchPy)
|
||||||
generate_from_xml(ViewProviderPy)
|
generate_from_xml(ViewProviderPy)
|
||||||
|
@ -97,8 +122,11 @@ set(Gui_MOC_HDRS
|
||||||
CallTips.h
|
CallTips.h
|
||||||
CombiView.h
|
CombiView.h
|
||||||
Control.h
|
Control.h
|
||||||
|
Clipping.h
|
||||||
DemoMode.h
|
DemoMode.h
|
||||||
DownloadDialog.h
|
DownloadDialog.h
|
||||||
|
DownloadItem.h
|
||||||
|
DownloadManager.h
|
||||||
DlgActionsImp.h
|
DlgActionsImp.h
|
||||||
DlgActivateWindowImp.h
|
DlgActivateWindowImp.h
|
||||||
DlgCommandsImp.h
|
DlgCommandsImp.h
|
||||||
|
@ -186,6 +214,7 @@ fc_wrap_cpp(Gui_MOC_SRCS ${Gui_MOC_HDRS})
|
||||||
|
|
||||||
SET(Gui_UIC_SRCS
|
SET(Gui_UIC_SRCS
|
||||||
AboutApplication.ui
|
AboutApplication.ui
|
||||||
|
Clipping.ui
|
||||||
DemoMode.ui
|
DemoMode.ui
|
||||||
DlgActions.ui
|
DlgActions.ui
|
||||||
DlgActivateWindow.ui
|
DlgActivateWindow.ui
|
||||||
|
@ -220,6 +249,8 @@ SET(Gui_UIC_SRCS
|
||||||
DlgTreeWidget.ui
|
DlgTreeWidget.ui
|
||||||
DlgLocationAngle.ui
|
DlgLocationAngle.ui
|
||||||
DlgLocationPos.ui
|
DlgLocationPos.ui
|
||||||
|
DownloadManager.ui
|
||||||
|
DownloadItem.ui
|
||||||
MouseButtons.ui
|
MouseButtons.ui
|
||||||
SceneInspector.ui
|
SceneInspector.ui
|
||||||
InputVector.ui
|
InputVector.ui
|
||||||
|
@ -260,6 +291,7 @@ SOURCE_GROUP("Command" FILES ${Command_SRCS})
|
||||||
|
|
||||||
# The dialog sources
|
# The dialog sources
|
||||||
SET(Dialog_CPP_SRCS
|
SET(Dialog_CPP_SRCS
|
||||||
|
Clipping.cpp
|
||||||
DemoMode.cpp
|
DemoMode.cpp
|
||||||
DlgActivateWindowImp.cpp
|
DlgActivateWindowImp.cpp
|
||||||
DlgDisplayPropertiesImp.cpp
|
DlgDisplayPropertiesImp.cpp
|
||||||
|
@ -282,9 +314,12 @@ SET(Dialog_CPP_SRCS
|
||||||
TextureMapping.cpp
|
TextureMapping.cpp
|
||||||
Transform.cpp
|
Transform.cpp
|
||||||
DownloadDialog.cpp
|
DownloadDialog.cpp
|
||||||
|
DownloadItem.cpp
|
||||||
|
DownloadManager.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(Dialog_HPP_SRCS
|
SET(Dialog_HPP_SRCS
|
||||||
|
Clipping.h
|
||||||
DemoMode.h
|
DemoMode.h
|
||||||
DlgActivateWindowImp.h
|
DlgActivateWindowImp.h
|
||||||
DlgDisplayPropertiesImp.h
|
DlgDisplayPropertiesImp.h
|
||||||
|
@ -307,17 +342,22 @@ SET(Dialog_HPP_SRCS
|
||||||
TextureMapping.h
|
TextureMapping.h
|
||||||
Transform.h
|
Transform.h
|
||||||
DownloadDialog.h
|
DownloadDialog.h
|
||||||
|
DownloadItem.h
|
||||||
|
DownloadManager.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(Dialog_SRCS
|
SET(Dialog_SRCS
|
||||||
${Dialog_CPP_SRCS}
|
${Dialog_CPP_SRCS}
|
||||||
${Dialog_HPP_SRCS}
|
${Dialog_HPP_SRCS}
|
||||||
AboutApplication.ui
|
AboutApplication.ui
|
||||||
|
Clipping.ui
|
||||||
DemoMode.ui
|
DemoMode.ui
|
||||||
DlgActivateWindow.ui
|
DlgActivateWindow.ui
|
||||||
DlgAuthorization.ui
|
DlgAuthorization.ui
|
||||||
DlgDisplayProperties.ui
|
DlgDisplayProperties.ui
|
||||||
DlgInputDialog.ui
|
DlgInputDialog.ui
|
||||||
|
DlgLocationAngle.ui
|
||||||
|
DlgLocationPos.ui
|
||||||
DlgMacroExecute.ui
|
DlgMacroExecute.ui
|
||||||
DlgRunExternal.ui
|
DlgRunExternal.ui
|
||||||
DlgMacroRecord.ui
|
DlgMacroRecord.ui
|
||||||
|
@ -327,6 +367,8 @@ SET(Dialog_SRCS
|
||||||
DlgProjectUtility.ui
|
DlgProjectUtility.ui
|
||||||
DlgTipOfTheDay.ui
|
DlgTipOfTheDay.ui
|
||||||
DlgTreeWidget.ui
|
DlgTreeWidget.ui
|
||||||
|
DownloadManager.ui
|
||||||
|
DownloadItem.ui
|
||||||
MouseButtons.ui
|
MouseButtons.ui
|
||||||
InputVector.ui
|
InputVector.ui
|
||||||
Placement.ui
|
Placement.ui
|
||||||
|
@ -884,7 +926,13 @@ else(WIN32)
|
||||||
INSTALL(TARGETS FreeCADGui
|
INSTALL(TARGETS FreeCADGui
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
)
|
)
|
||||||
INSTALL(FILES Icons/freecad.xpm Icons/freecad-doc.png
|
INSTALL(FILES Icons/freecad.xpm
|
||||||
|
Icons/freecad-icon-16.png
|
||||||
|
Icons/freecad-icon-32.png
|
||||||
|
Icons/freecad-icon-48.png
|
||||||
|
Icons/freecad-icon-64.png
|
||||||
|
Icons/freecad.svg
|
||||||
|
Icons/freecad-doc.png
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}
|
DESTINATION ${CMAKE_INSTALL_DATADIR}
|
||||||
)
|
)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
315
src/Gui/Clipping.cpp
Normal file
315
src/Gui/Clipping.cpp
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "PreCompiled.h"
|
||||||
|
#ifndef _PreComp_
|
||||||
|
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||||
|
# include <Inventor/nodes/SoClipPlane.h>
|
||||||
|
# include <Inventor/nodes/SoGroup.h>
|
||||||
|
# include <QPointer>
|
||||||
|
#endif
|
||||||
|
# include <Inventor/sensors/SoTimerSensor.h>
|
||||||
|
|
||||||
|
#include "Clipping.h"
|
||||||
|
#include "ui_Clipping.h"
|
||||||
|
#include "Application.h"
|
||||||
|
#include "View3DInventor.h"
|
||||||
|
#include "View3DInventorViewer.h"
|
||||||
|
|
||||||
|
using namespace Gui::Dialog;
|
||||||
|
|
||||||
|
class Clipping::Private {
|
||||||
|
public:
|
||||||
|
Ui_Clipping ui;
|
||||||
|
QPointer<Gui::View3DInventor> view;
|
||||||
|
SoGroup* node;
|
||||||
|
SoClipPlane* clipX;
|
||||||
|
SoClipPlane* clipY;
|
||||||
|
SoClipPlane* clipZ;
|
||||||
|
SoClipPlane* clipView;
|
||||||
|
bool flipX;
|
||||||
|
bool flipY;
|
||||||
|
bool flipZ;
|
||||||
|
SoTimerSensor* sensor;
|
||||||
|
Private() : flipX(false), flipY(false), flipZ(false)
|
||||||
|
{
|
||||||
|
clipX = new SoClipPlane();
|
||||||
|
clipX->on.setValue(false);
|
||||||
|
clipX->plane.setValue(SbPlane(SbVec3f(1,0,0),0));
|
||||||
|
clipX->ref();
|
||||||
|
|
||||||
|
clipY = new SoClipPlane();
|
||||||
|
clipY->on.setValue(false);
|
||||||
|
clipY->plane.setValue(SbPlane(SbVec3f(0,1,0),0));
|
||||||
|
clipY->ref();
|
||||||
|
|
||||||
|
clipZ = new SoClipPlane();
|
||||||
|
clipZ->on.setValue(false);
|
||||||
|
clipZ->plane.setValue(SbPlane(SbVec3f(0,0,1),0));
|
||||||
|
clipZ->ref();
|
||||||
|
|
||||||
|
clipView = new SoClipPlane();
|
||||||
|
clipView->on.setValue(false);
|
||||||
|
clipView->plane.setValue(SbPlane(SbVec3f(0,0,1),0));
|
||||||
|
clipView->ref();
|
||||||
|
|
||||||
|
sensor = new SoTimerSensor(moveCallback, this);
|
||||||
|
}
|
||||||
|
~Private()
|
||||||
|
{
|
||||||
|
clipX->unref();
|
||||||
|
clipY->unref();
|
||||||
|
clipZ->unref();
|
||||||
|
clipView->unref();
|
||||||
|
delete sensor;
|
||||||
|
}
|
||||||
|
static void moveCallback(void * data, SoSensor * sensor)
|
||||||
|
{
|
||||||
|
Private* self = reinterpret_cast<Private*>(data);
|
||||||
|
if (self->view) {
|
||||||
|
Gui::View3DInventorViewer* view = self->view->getViewer();
|
||||||
|
SoClipPlane* clip = self->clipView;
|
||||||
|
SbPlane pln = clip->plane.getValue();
|
||||||
|
clip->plane.setValue(SbPlane(view->getViewDirection(),pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TRANSLATOR Gui::Dialog::Clipping */
|
||||||
|
|
||||||
|
Clipping::Clipping(Gui::View3DInventor* view, QWidget* parent)
|
||||||
|
: QWidget(parent), d(new Private)
|
||||||
|
{
|
||||||
|
// create widgets
|
||||||
|
d->ui.setupUi(this);
|
||||||
|
d->ui.clipView->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.clipView->setSingleStep(0.1f);
|
||||||
|
d->ui.clipX->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.clipX->setSingleStep(0.1f);
|
||||||
|
d->ui.clipY->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.clipY->setSingleStep(0.1f);
|
||||||
|
d->ui.clipZ->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.clipZ->setSingleStep(0.1f);
|
||||||
|
|
||||||
|
d->ui.dirX->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.dirX->setSingleStep(0.1f);
|
||||||
|
d->ui.dirY->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.dirY->setSingleStep(0.1f);
|
||||||
|
d->ui.dirZ->setRange(-INT_MAX,INT_MAX);
|
||||||
|
d->ui.dirZ->setSingleStep(0.1f);
|
||||||
|
d->ui.dirZ->setValue(1.0f);
|
||||||
|
|
||||||
|
d->view = view;
|
||||||
|
View3DInventorViewer* viewer = view->getViewer();
|
||||||
|
d->node = static_cast<SoGroup*>(viewer->getSceneGraph());
|
||||||
|
d->node->ref();
|
||||||
|
d->node->insertChild(d->clipX, 0);
|
||||||
|
d->node->insertChild(d->clipY, 0);
|
||||||
|
d->node->insertChild(d->clipZ, 0);
|
||||||
|
d->node->insertChild(d->clipView, 0);
|
||||||
|
|
||||||
|
SoGetBoundingBoxAction action(viewer->getViewportRegion());
|
||||||
|
action.apply(viewer->getSceneGraph());
|
||||||
|
SbBox3f box = action.getBoundingBox();
|
||||||
|
|
||||||
|
if (!box.isEmpty()) {
|
||||||
|
SbVec3f cnt = box.getCenter();
|
||||||
|
d->ui.clipView->setValue(cnt[2]);
|
||||||
|
d->ui.clipX->setValue(cnt[0]);
|
||||||
|
d->ui.clipY->setValue(cnt[1]);
|
||||||
|
d->ui.clipZ->setValue(cnt[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destroys the object and frees any allocated resources */
|
||||||
|
Clipping::~Clipping()
|
||||||
|
{
|
||||||
|
d->node->removeChild(d->clipX);
|
||||||
|
d->node->removeChild(d->clipY);
|
||||||
|
d->node->removeChild(d->clipZ);
|
||||||
|
d->node->removeChild(d->clipView);
|
||||||
|
d->node->unref();
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_groupBoxX_toggled(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
d->ui.groupBoxView->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->clipX->on.setValue(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_groupBoxY_toggled(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
d->ui.groupBoxView->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->clipY->on.setValue(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_groupBoxZ_toggled(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
d->ui.groupBoxView->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->clipZ->on.setValue(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_clipX_valueChanged(double val)
|
||||||
|
{
|
||||||
|
SbPlane pln = d->clipX->plane.getValue();
|
||||||
|
d->clipX->plane.setValue(SbPlane(pln.getNormal(),d->flipX ? -val : val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_clipY_valueChanged(double val)
|
||||||
|
{
|
||||||
|
SbPlane pln = d->clipY->plane.getValue();
|
||||||
|
d->clipY->plane.setValue(SbPlane(pln.getNormal(),d->flipY ? -val : val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_clipZ_valueChanged(double val)
|
||||||
|
{
|
||||||
|
SbPlane pln = d->clipZ->plane.getValue();
|
||||||
|
d->clipZ->plane.setValue(SbPlane(pln.getNormal(),d->flipZ ? -val : val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_flipClipX_clicked()
|
||||||
|
{
|
||||||
|
d->flipX = !d->flipX;
|
||||||
|
SbPlane pln = d->clipX->plane.getValue();
|
||||||
|
d->clipX->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_flipClipY_clicked()
|
||||||
|
{
|
||||||
|
d->flipY = !d->flipY;
|
||||||
|
SbPlane pln = d->clipY->plane.getValue();
|
||||||
|
d->clipY->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_flipClipZ_clicked()
|
||||||
|
{
|
||||||
|
d->flipZ = !d->flipZ;
|
||||||
|
SbPlane pln = d->clipZ->plane.getValue();
|
||||||
|
d->clipZ->plane.setValue(SbPlane(-pln.getNormal(),-pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_groupBoxView_toggled(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
d->ui.groupBoxX->setChecked(false);
|
||||||
|
d->ui.groupBoxY->setChecked(false);
|
||||||
|
d->ui.groupBoxZ->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->clipView->on.setValue(on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_clipView_valueChanged(double val)
|
||||||
|
{
|
||||||
|
SbPlane pln = d->clipView->plane.getValue();
|
||||||
|
d->clipView->plane.setValue(SbPlane(pln.getNormal(),val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_fromView_clicked()
|
||||||
|
{
|
||||||
|
if (d->view) {
|
||||||
|
Gui::View3DInventorViewer* view = d->view->getViewer();
|
||||||
|
SbVec3f dir = view->getViewDirection();
|
||||||
|
SbPlane pln = d->clipView->plane.getValue();
|
||||||
|
d->clipView->plane.setValue(SbPlane(dir,pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_adjustViewdirection_toggled(bool on)
|
||||||
|
{
|
||||||
|
d->ui.dirX->setDisabled(on);
|
||||||
|
d->ui.dirY->setDisabled(on);
|
||||||
|
d->ui.dirZ->setDisabled(on);
|
||||||
|
d->ui.fromView->setDisabled(on);
|
||||||
|
|
||||||
|
if (on)
|
||||||
|
d->sensor->schedule();
|
||||||
|
else
|
||||||
|
d->sensor->unschedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_dirX_valueChanged(double)
|
||||||
|
{
|
||||||
|
double x = d->ui.dirX->value();
|
||||||
|
double y = d->ui.dirY->value();
|
||||||
|
double z = d->ui.dirZ->value();
|
||||||
|
|
||||||
|
SbPlane pln = d->clipView->plane.getValue();
|
||||||
|
SbVec3f normal(x,y,z);
|
||||||
|
if (normal.sqrLength() > 0.0f)
|
||||||
|
d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_dirY_valueChanged(double)
|
||||||
|
{
|
||||||
|
double x = d->ui.dirX->value();
|
||||||
|
double y = d->ui.dirY->value();
|
||||||
|
double z = d->ui.dirZ->value();
|
||||||
|
|
||||||
|
SbPlane pln = d->clipView->plane.getValue();
|
||||||
|
SbVec3f normal(x,y,z);
|
||||||
|
if (normal.sqrLength() > 0.0f)
|
||||||
|
d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clipping::on_dirZ_valueChanged(double)
|
||||||
|
{
|
||||||
|
double x = d->ui.dirX->value();
|
||||||
|
double y = d->ui.dirY->value();
|
||||||
|
double z = d->ui.dirZ->value();
|
||||||
|
|
||||||
|
SbPlane pln = d->clipView->plane.getValue();
|
||||||
|
SbVec3f normal(x,y,z);
|
||||||
|
if (normal.sqrLength() > 0.0f)
|
||||||
|
d->clipView->plane.setValue(SbPlane(normal,pln.getDistanceFromOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------
|
||||||
|
|
||||||
|
/* TRANSLATOR Gui::Dialog::TaskClipping */
|
||||||
|
|
||||||
|
TaskClipping::TaskClipping(Gui::View3DInventor* view)
|
||||||
|
{
|
||||||
|
QWidget* widget = new Clipping(view);
|
||||||
|
Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox(
|
||||||
|
QPixmap(), widget->windowTitle(), false, 0);
|
||||||
|
taskbox->groupLayout()->addWidget(widget);
|
||||||
|
Content.push_back(taskbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskClipping::~TaskClipping()
|
||||||
|
{
|
||||||
|
// automatically deleted in the sub-class
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_Clipping.cpp"
|
88
src/Gui/Clipping.h
Normal file
88
src/Gui/Clipping.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GUI_DIALOG_CLIPPING_H
|
||||||
|
#define GUI_DIALOG_CLIPPING_H
|
||||||
|
|
||||||
|
#include <Gui/TaskView/TaskDialog.h>
|
||||||
|
#include <Gui/TaskView/TaskView.h>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Gui {
|
||||||
|
class View3DInventor;
|
||||||
|
namespace Dialog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Werner Mayer
|
||||||
|
*/
|
||||||
|
class GuiExport Clipping : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Clipping(Gui::View3DInventor* view, QWidget* parent = 0);
|
||||||
|
~Clipping();
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void on_groupBoxX_toggled(bool);
|
||||||
|
void on_groupBoxY_toggled(bool);
|
||||||
|
void on_groupBoxZ_toggled(bool);
|
||||||
|
void on_clipX_valueChanged(double);
|
||||||
|
void on_clipY_valueChanged(double);
|
||||||
|
void on_clipZ_valueChanged(double);
|
||||||
|
void on_flipClipX_clicked();
|
||||||
|
void on_flipClipY_clicked();
|
||||||
|
void on_flipClipZ_clicked();
|
||||||
|
void on_groupBoxView_toggled(bool);
|
||||||
|
void on_clipView_valueChanged(double);
|
||||||
|
void on_fromView_clicked();
|
||||||
|
void on_adjustViewdirection_toggled(bool);
|
||||||
|
void on_dirX_valueChanged(double);
|
||||||
|
void on_dirY_valueChanged(double);
|
||||||
|
void on_dirZ_valueChanged(double);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Private;
|
||||||
|
Private* d;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embed the panel into a task dialog.
|
||||||
|
*/
|
||||||
|
class TaskClipping : public Gui::TaskView::TaskDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TaskClipping(Gui::View3DInventor* view);
|
||||||
|
~TaskClipping();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual QDialogButtonBox::StandardButtons getStandardButtons() const
|
||||||
|
{ return QDialogButtonBox::Close; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialog
|
||||||
|
} // namespace Gui
|
||||||
|
|
||||||
|
#endif // GUI_DIALOG_CLIPPING_H
|
244
src/Gui/Clipping.ui
Normal file
244
src/Gui/Clipping.ui
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Gui::Dialog::Clipping</class>
|
||||||
|
<widget class="QWidget" name="Gui::Dialog::Clipping">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>304</width>
|
||||||
|
<height>430</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Clipping</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBoxX">
|
||||||
|
<property name="title">
|
||||||
|
<string>Clipping X</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="clipX"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QPushButton" name="flipClipX">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flip</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Offset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBoxY">
|
||||||
|
<property name="title">
|
||||||
|
<string>Clipping Y</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="clipY"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QPushButton" name="flipClipY">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flip</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Offset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBoxZ">
|
||||||
|
<property name="title">
|
||||||
|
<string>Clipping Z</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="clipZ"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QPushButton" name="flipClipZ">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flip</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Offset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBoxView">
|
||||||
|
<property name="title">
|
||||||
|
<string>Clipping custom direction</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_6">
|
||||||
|
<item row="0" column="3">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>84</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QPushButton" name="fromView">
|
||||||
|
<property name="text">
|
||||||
|
<string>View</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="5">
|
||||||
|
<widget class="QCheckBox" name="adjustViewdirection">
|
||||||
|
<property name="text">
|
||||||
|
<string>Adjust to view direction</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="5">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Direction</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="dirX"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="dirY"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="dirZ"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Offset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QDoubleSpinBox" name="clipView"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>groupBoxX</tabstop>
|
||||||
|
<tabstop>clipX</tabstop>
|
||||||
|
<tabstop>flipClipX</tabstop>
|
||||||
|
<tabstop>groupBoxY</tabstop>
|
||||||
|
<tabstop>clipY</tabstop>
|
||||||
|
<tabstop>flipClipY</tabstop>
|
||||||
|
<tabstop>groupBoxZ</tabstop>
|
||||||
|
<tabstop>clipZ</tabstop>
|
||||||
|
<tabstop>flipClipZ</tabstop>
|
||||||
|
<tabstop>groupBoxView</tabstop>
|
||||||
|
<tabstop>clipView</tabstop>
|
||||||
|
<tabstop>fromView</tabstop>
|
||||||
|
<tabstop>adjustViewdirection</tabstop>
|
||||||
|
<tabstop>dirX</tabstop>
|
||||||
|
<tabstop>dirY</tabstop>
|
||||||
|
<tabstop>dirZ</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -581,6 +581,12 @@ void Command::applyCommandData(Action* action)
|
||||||
action->setWhatsThis(QCoreApplication::translate(
|
action->setWhatsThis(QCoreApplication::translate(
|
||||||
this->className(), sToolTipText, 0,
|
this->className(), sToolTipText, 0,
|
||||||
QCoreApplication::UnicodeUTF8));
|
QCoreApplication::UnicodeUTF8));
|
||||||
|
QString accel = action->shortcut().toString();
|
||||||
|
if (!accel.isEmpty()) {
|
||||||
|
QString tip = QString::fromAscii("(%1)\t%2")
|
||||||
|
.arg(accel).arg(action->statusTip());
|
||||||
|
action->setStatusTip(tip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Command::keySequenceToAccel(int sk) const
|
const char* Command::keySequenceToAccel(int sk) const
|
||||||
|
|
|
@ -841,7 +841,6 @@ void StdCmdCopy::activated(int iMsg)
|
||||||
{
|
{
|
||||||
bool done = getGuiApplication()->sendMsgToActiveView("Copy");
|
bool done = getGuiApplication()->sendMsgToActiveView("Copy");
|
||||||
if (!done) {
|
if (!done) {
|
||||||
WaitCursor wc;
|
|
||||||
QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection();
|
QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection();
|
||||||
QClipboard* cb = QApplication::clipboard();
|
QClipboard* cb = QApplication::clipboard();
|
||||||
cb->setMimeData(mimeData);
|
cb->setMimeData(mimeData);
|
||||||
|
@ -910,59 +909,54 @@ StdCmdDuplicateSelection::StdCmdDuplicateSelection()
|
||||||
|
|
||||||
void StdCmdDuplicateSelection::activated(int iMsg)
|
void StdCmdDuplicateSelection::activated(int iMsg)
|
||||||
{
|
{
|
||||||
App::Document* act = App::GetApplication().getActiveDocument();
|
std::vector<SelectionSingleton::SelObj> sel = Selection().getCompleteSelection();
|
||||||
if (!act)
|
std::map< App::Document*, std::vector<App::DocumentObject*> > objs;
|
||||||
return; // no active document found
|
|
||||||
Gui::Document* doc = Gui::Application::Instance->getDocument(act);
|
|
||||||
std::vector<Gui::SelectionSingleton::SelObj> sel = Gui::Selection().getCompleteSelection();
|
|
||||||
for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
|
for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
|
||||||
if (!it->pObject)
|
if (it->pObject && it->pObject->getDocument()) {
|
||||||
continue; // should actually not happen
|
objs[it->pObject->getDocument()].push_back(it->pObject);
|
||||||
// create a copy of the object
|
|
||||||
App::DocumentObject* copy = act->copyObject(it->pObject, false);
|
|
||||||
if (!copy) // continue if no copy could be created
|
|
||||||
continue;
|
|
||||||
// mark all properties of the copy as "touched" which are touched in the original object
|
|
||||||
std::map<std::string,App::Property*> props;
|
|
||||||
it->pObject->getPropertyMap(props);
|
|
||||||
std::map<std::string,App::Property*> copy_props;
|
|
||||||
copy->getPropertyMap(copy_props);
|
|
||||||
for (std::map<std::string,App::Property*>::iterator jt = props.begin(); jt != props.end(); ++jt) {
|
|
||||||
if (jt->second->isTouched()) {
|
|
||||||
std::map<std::string,App::Property*>::iterator kt;
|
|
||||||
kt = copy_props.find(jt->first);
|
|
||||||
if (kt != copy_props.end()) {
|
|
||||||
kt->second->touch();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gui::Document* parent = Gui::Application::Instance->getDocument(it->pObject->getDocument());
|
if (objs.empty())
|
||||||
if (!parent || !doc)
|
return;
|
||||||
continue; // should not happen
|
|
||||||
// copy the properties of the associated view providers
|
|
||||||
Gui::ViewProvider* view = parent->getViewProvider(it->pObject);
|
|
||||||
Gui::ViewProvider* copy_view = doc->getViewProvider(copy);
|
|
||||||
copy_view->addDynamicProperties(view);
|
|
||||||
if (!view || !copy_view)
|
|
||||||
continue; // should not happen
|
|
||||||
|
|
||||||
// get the properties of the view provider
|
Base::FileInfo fi(Base::FileInfo::getTempFileName());
|
||||||
props.clear();
|
{
|
||||||
view->getPropertyMap(props);
|
std::vector<App::DocumentObject*> sel; // selected
|
||||||
copy_props.clear();
|
std::vector<App::DocumentObject*> all; // object sub-graph
|
||||||
copy_view->getPropertyMap(copy_props);
|
for (std::map< App::Document*, std::vector<App::DocumentObject*> >::iterator it = objs.begin(); it != objs.end(); ++it) {
|
||||||
for (std::map<std::string,App::Property*>::iterator jt = props.begin(); jt != props.end(); ++jt) {
|
std::vector<App::DocumentObject*> dep = it->first->getDependencyList(it->second);
|
||||||
std::map<std::string,App::Property*>::iterator kt;
|
sel.insert(sel.end(), it->second.begin(), it->second.end());
|
||||||
kt = copy_props.find(jt->first);
|
all.insert(all.end(), dep.begin(), dep.end());
|
||||||
if (kt != copy_props.end()) {
|
}
|
||||||
std::auto_ptr<App::Property> data(jt->second->Copy());
|
|
||||||
if (data.get()) {
|
if (all.size() > sel.size()) {
|
||||||
kt->second->Paste(*data);
|
int ret = QMessageBox::question(getMainWindow(),
|
||||||
|
qApp->translate("Std_DuplicateSelection","Object dependencies"),
|
||||||
|
qApp->translate("Std_DuplicateSelection","The selected objects have a dependency to unselected objects.\n"
|
||||||
|
"Do you want to duplicate them, too?"),
|
||||||
|
QMessageBox::Yes,QMessageBox::No);
|
||||||
|
if (ret == QMessageBox::Yes) {
|
||||||
|
sel = all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save stuff to file
|
||||||
|
Base::ofstream str(fi, std::ios::out | std::ios::binary);
|
||||||
|
App::Document* doc = sel.front()->getDocument();
|
||||||
|
MergeDocuments mimeView(doc);
|
||||||
|
doc->exportObjects(sel, str);
|
||||||
|
str.close();
|
||||||
}
|
}
|
||||||
|
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||||
|
if (doc) {
|
||||||
|
// restore objects from file and add to active document
|
||||||
|
Base::ifstream str(fi, std::ios::in | std::ios::binary);
|
||||||
|
MergeDocuments mimeView(doc);
|
||||||
|
mimeView.importObjects(str);
|
||||||
|
str.close();
|
||||||
}
|
}
|
||||||
|
fi.deleteFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StdCmdDuplicateSelection::isActive(void)
|
bool StdCmdDuplicateSelection::isActive(void)
|
||||||
|
@ -1032,11 +1026,45 @@ void StdCmdDelete::activated(int iMsg)
|
||||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(*it);
|
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(*it);
|
||||||
std::vector<Gui::SelectionObject> sel = rSel.getSelectionEx((*it)->getName());
|
std::vector<Gui::SelectionObject> sel = rSel.getSelectionEx((*it)->getName());
|
||||||
if (!sel.empty()) {
|
if (!sel.empty()) {
|
||||||
|
bool doDeletion = true;
|
||||||
|
// check if we can delete the object
|
||||||
|
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
|
||||||
|
App::DocumentObject* obj = ft->getObject();
|
||||||
|
Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject());
|
||||||
|
// if the object is in edit mode we allow to continue because only sub-elements will be removed
|
||||||
|
if (!vp || !vp->isEditing()) {
|
||||||
|
std::vector<App::DocumentObject*> links = obj->getInList();
|
||||||
|
if (!links.empty()) {
|
||||||
|
// check if the referenced objects are groups or are selected too
|
||||||
|
for (std::vector<App::DocumentObject*>::iterator lt = links.begin(); lt != links.end(); ++lt) {
|
||||||
|
if (!(*lt)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) && !rSel.isSelected(*lt)) {
|
||||||
|
doDeletion = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doDeletion) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doDeletion) {
|
||||||
|
int ret = QMessageBox::question(Gui::getMainWindow(),
|
||||||
|
qApp->translate("Std_Delete", "Object dependencies"),
|
||||||
|
qApp->translate("Std_Delete", "This object is referenced by other objects and thus these objects might get broken.\n"
|
||||||
|
"Are you sure to continue?"),
|
||||||
|
QMessageBox::Yes, QMessageBox::No);
|
||||||
|
if (ret == QMessageBox::Yes)
|
||||||
|
doDeletion = true;
|
||||||
|
}
|
||||||
|
if (doDeletion) {
|
||||||
(*it)->openTransaction("Delete");
|
(*it)->openTransaction("Delete");
|
||||||
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
|
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
|
||||||
Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject());
|
Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject());
|
||||||
if (vp) {
|
if (vp) {
|
||||||
// ask the ViewProvider if its want to do some clean up
|
// ask the ViewProvider if it wants to do some clean up
|
||||||
if (vp->onDelete(ft->getSubNames()))
|
if (vp->onDelete(ft->getSubNames()))
|
||||||
doCommand(Doc,"App.getDocument(\"%s\").removeObject(\"%s\")"
|
doCommand(Doc,"App.getDocument(\"%s\").removeObject(\"%s\")"
|
||||||
,(*it)->getName(), ft->getFeatName());
|
,(*it)->getName(), ft->getFeatName());
|
||||||
|
@ -1046,6 +1074,7 @@ void StdCmdDelete::activated(int iMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool StdCmdDelete::isActive(void)
|
bool StdCmdDelete::isActive(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BitmapFactory.h"
|
#include "BitmapFactory.h"
|
||||||
#include "Control.h"
|
#include "Control.h"
|
||||||
|
#include "Clipping.h"
|
||||||
#include "FileDialog.h"
|
#include "FileDialog.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "Tree.h"
|
#include "Tree.h"
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
#include "Selection.h"
|
#include "Selection.h"
|
||||||
#include "SoFCOffscreenRenderer.h"
|
#include "SoFCOffscreenRenderer.h"
|
||||||
#include "SoFCBoundingBox.h"
|
#include "SoFCBoundingBox.h"
|
||||||
|
#include "SoFCUnifiedSelection.h"
|
||||||
#include "SoAxisCrossKit.h"
|
#include "SoAxisCrossKit.h"
|
||||||
#include "View3DInventor.h"
|
#include "View3DInventor.h"
|
||||||
#include "View3DInventorViewer.h"
|
#include "View3DInventorViewer.h"
|
||||||
|
@ -473,12 +475,15 @@ StdCmdToggleClipPlane::StdCmdToggleClipPlane()
|
||||||
Action * StdCmdToggleClipPlane::createAction(void)
|
Action * StdCmdToggleClipPlane::createAction(void)
|
||||||
{
|
{
|
||||||
Action *pcAction = (Action*)Command::createAction();
|
Action *pcAction = (Action*)Command::createAction();
|
||||||
|
#if 0
|
||||||
pcAction->setCheckable(true);
|
pcAction->setCheckable(true);
|
||||||
|
#endif
|
||||||
return pcAction;
|
return pcAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StdCmdToggleClipPlane::activated(int iMsg)
|
void StdCmdToggleClipPlane::activated(int iMsg)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
||||||
if (view) {
|
if (view) {
|
||||||
if (iMsg > 0 && !view->hasClippingPlane())
|
if (iMsg > 0 && !view->hasClippingPlane())
|
||||||
|
@ -486,10 +491,17 @@ void StdCmdToggleClipPlane::activated(int iMsg)
|
||||||
else if (iMsg == 0 && view->hasClippingPlane())
|
else if (iMsg == 0 && view->hasClippingPlane())
|
||||||
view->toggleClippingPlane();
|
view->toggleClippingPlane();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
||||||
|
if (view) {
|
||||||
|
Gui::Control().showDialog(new Gui::Dialog::TaskClipping(view));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StdCmdToggleClipPlane::isActive(void)
|
bool StdCmdToggleClipPlane::isActive(void)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
||||||
if (view) {
|
if (view) {
|
||||||
Action* action = qobject_cast<Action*>(_pcAction);
|
Action* action = qobject_cast<Action*>(_pcAction);
|
||||||
|
@ -503,6 +515,11 @@ bool StdCmdToggleClipPlane::isActive(void)
|
||||||
action->setChecked(false);
|
action->setChecked(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (Gui::Control().activeDialog())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_STD_CMD_ACL(StdCmdDrawStyle);
|
DEF_STD_CMD_ACL(StdCmdDrawStyle);
|
||||||
|
@ -1922,6 +1939,9 @@ static void selectionCallback(void * ud, SoEventCallback * cb)
|
||||||
{
|
{
|
||||||
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(cb->getUserData());
|
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(cb->getUserData());
|
||||||
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud);
|
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud);
|
||||||
|
SoNode* root = view->getSceneGraph();
|
||||||
|
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(TRUE);
|
||||||
|
|
||||||
std::vector<SbVec2f> picked = view->getGLPolygon();
|
std::vector<SbVec2f> picked = view->getGLPolygon();
|
||||||
SoCamera* cam = view->getCamera();
|
SoCamera* cam = view->getCamera();
|
||||||
SbViewVolume vv = cam->getViewVolume();
|
SbViewVolume vv = cam->getViewVolume();
|
||||||
|
@ -1972,8 +1992,10 @@ void StdBoxSelection::activated(int iMsg)
|
||||||
if (view) {
|
if (view) {
|
||||||
View3DInventorViewer* viewer = view->getViewer();
|
View3DInventorViewer* viewer = view->getViewer();
|
||||||
if (!viewer->isSelecting()) {
|
if (!viewer->isSelecting()) {
|
||||||
viewer->startSelection(View3DInventorViewer::Rectangle);
|
viewer->startSelection(View3DInventorViewer::Rubberband);
|
||||||
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback);
|
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback);
|
||||||
|
SoNode* root = viewer->getSceneGraph();
|
||||||
|
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
# include <cmath>
|
# include <cmath>
|
||||||
# include <float.h>
|
# include <float.h>
|
||||||
# include <climits>
|
# include <climits>
|
||||||
|
# include <QCursor>
|
||||||
# include <QTimer>
|
# include <QTimer>
|
||||||
#include <Inventor/nodes/SoCamera.h>
|
#include <Inventor/nodes/SoCamera.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -53,6 +54,11 @@ DemoMode::DemoMode(QWidget* parent, Qt::WFlags fl)
|
||||||
timer->setInterval(1000 * ui->timeout->value());
|
timer->setInterval(1000 * ui->timeout->value());
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(onAutoPlay()));
|
connect(timer, SIGNAL(timeout()), this, SLOT(onAutoPlay()));
|
||||||
oldvalue = ui->angleSlider->value();
|
oldvalue = ui->angleSlider->value();
|
||||||
|
|
||||||
|
wasHidden = false;
|
||||||
|
showHideTimer = new QTimer(this);
|
||||||
|
showHideTimer->setInterval(5000);
|
||||||
|
connect(showHideTimer, SIGNAL(timeout()), this, SLOT(hide()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Destroys the object and frees any allocated resources */
|
/** Destroys the object and frees any allocated resources */
|
||||||
|
@ -82,6 +88,35 @@ void DemoMode::reject()
|
||||||
QDialog::reject();
|
QDialog::reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DemoMode::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::MouseMove) {
|
||||||
|
if (ui->fullscreen->isChecked()) {
|
||||||
|
QPoint point = QCursor::pos() - oldPos;
|
||||||
|
if (point.manhattanLength() > 5) {
|
||||||
|
show();
|
||||||
|
showHideTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QDialog::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemoMode::showEvent(QShowEvent *)
|
||||||
|
{
|
||||||
|
if (this->wasHidden)
|
||||||
|
this->move(this->pnt);
|
||||||
|
this->wasHidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemoMode::hideEvent(QHideEvent *)
|
||||||
|
{
|
||||||
|
this->pnt = this->pos();
|
||||||
|
this->wasHidden = true;
|
||||||
|
this->oldPos = QCursor::pos();
|
||||||
|
showHideTimer->stop();
|
||||||
|
}
|
||||||
|
|
||||||
Gui::View3DInventor* DemoMode::activeView() const
|
Gui::View3DInventor* DemoMode::activeView() const
|
||||||
{
|
{
|
||||||
Document* doc = Application::Instance->activeDocument();
|
Document* doc = Application::Instance->activeDocument();
|
||||||
|
@ -186,6 +221,14 @@ void DemoMode::on_fullscreen_toggled(bool on)
|
||||||
view->setCurrentViewMode(on ? MDIView::/*TopLevel*/FullScreen : MDIView::Child);
|
view->setCurrentViewMode(on ? MDIView::/*TopLevel*/FullScreen : MDIView::Child);
|
||||||
this->activateWindow();
|
this->activateWindow();
|
||||||
}
|
}
|
||||||
|
if (on) {
|
||||||
|
qApp->installEventFilter(this);
|
||||||
|
showHideTimer->start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qApp->removeEventFilter(this);
|
||||||
|
showHideTimer->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemoMode::on_timeout_valueChanged(int v)
|
void DemoMode::on_timeout_valueChanged(int v)
|
||||||
|
|
|
@ -68,12 +68,19 @@ private:
|
||||||
Gui::View3DInventor* activeView() const;
|
Gui::View3DInventor* activeView() const;
|
||||||
void startAnimation(Gui::View3DInventor*);
|
void startAnimation(Gui::View3DInventor*);
|
||||||
void changeEvent(QEvent *e);
|
void changeEvent(QEvent *e);
|
||||||
|
bool eventFilter(QObject *, QEvent *);
|
||||||
|
void showEvent(QShowEvent *);
|
||||||
|
void hideEvent(QHideEvent *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int oldvalue;
|
int oldvalue;
|
||||||
SbVec3f viewAxis;
|
SbVec3f viewAxis;
|
||||||
|
bool wasHidden;
|
||||||
|
QPoint pnt;
|
||||||
|
QPoint oldPos;
|
||||||
Ui_DemoMode* ui;
|
Ui_DemoMode* ui;
|
||||||
QTimer* timer;
|
QTimer* timer;
|
||||||
|
QTimer* showHideTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dialog
|
} // namespace Dialog
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<author></author>
|
|
||||||
<comment></comment>
|
|
||||||
<exportmacro></exportmacro>
|
|
||||||
<class>Gui::Dialog::DlgAuthorization</class>
|
<class>Gui::Dialog::DlgAuthorization</class>
|
||||||
<widget class="QDialog" name="Gui::Dialog::DlgAuthorization">
|
<widget class="QDialog" name="Gui::Dialog::DlgAuthorization">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>304</width>
|
<width>284</width>
|
||||||
<height>189</height>
|
<height>128</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -18,74 +16,16 @@
|
||||||
<property name="sizeGripEnabled">
|
<property name="sizeGripEnabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" >
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<property name="margin" >
|
<item row="1" column="0">
|
||||||
<number>11</number>
|
<widget class="QLabel" name="textLabel1">
|
||||||
</property>
|
|
||||||
<property name="spacing" >
|
|
||||||
<number>6</number>
|
|
||||||
</property>
|
|
||||||
<item row="5" column="0" >
|
|
||||||
<layout class="QHBoxLayout" >
|
|
||||||
<property name="margin" >
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="spacing" >
|
|
||||||
<number>6</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="buttonOk" >
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&OK</string>
|
<string>Username:</string>
|
||||||
</property>
|
|
||||||
<property name="shortcut" >
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="default" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="1">
|
||||||
<spacer>
|
<widget class="QLineEdit" name="username"/>
|
||||||
<property name="orientation" >
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType" >
|
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" >
|
|
||||||
<size>
|
|
||||||
<width>140</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="buttonCancel" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>&Cancel</string>
|
|
||||||
</property>
|
|
||||||
<property name="shortcut" >
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="autoDefault" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0" >
|
|
||||||
<widget class="QLineEdit" name="password" >
|
|
||||||
<property name="echoMode" >
|
|
||||||
<enum>QLineEdit::Password</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="textLabel2">
|
<widget class="QLabel" name="textLabel2">
|
||||||
|
@ -94,17 +34,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0" >
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="username" />
|
<widget class="QLineEdit" name="password">
|
||||||
</item>
|
<property name="echoMode">
|
||||||
<item row="0" column="0" >
|
<enum>QLineEdit::Password</enum>
|
||||||
<widget class="QLabel" name="textLabel1" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>User name:</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0" >
|
<item row="3" column="0" colspan="2">
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
@ -112,7 +49,7 @@
|
||||||
<property name="sizeType">
|
<property name="sizeType">
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
<enum>QSizePolicy::Expanding</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" >
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>21</width>
|
<width>21</width>
|
||||||
<height>41</height>
|
<height>41</height>
|
||||||
|
@ -120,48 +57,43 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Site:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="siteDescription">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>%1 at %2</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>username</tabstop>
|
<tabstop>username</tabstop>
|
||||||
<tabstop>password</tabstop>
|
<tabstop>password</tabstop>
|
||||||
<tabstop>buttonOk</tabstop>
|
|
||||||
<tabstop>buttonCancel</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>buttonOk</sender>
|
|
||||||
<signal>clicked()</signal>
|
|
||||||
<receiver>Gui::Dialog::DlgAuthorization</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel" >
|
|
||||||
<x>20</x>
|
|
||||||
<y>20</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel" >
|
|
||||||
<x>20</x>
|
|
||||||
<y>20</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonCancel</sender>
|
|
||||||
<signal>clicked()</signal>
|
|
||||||
<receiver>Gui::Dialog::DlgAuthorization</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel" >
|
|
||||||
<x>20</x>
|
|
||||||
<y>20</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel" >
|
|
||||||
<x>20</x>
|
|
||||||
<y>20</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -40,9 +40,6 @@
|
||||||
<property name="spacing" >
|
<property name="spacing" >
|
||||||
<number>6</number>
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
<item rowspan="2" row="7" column="1" >
|
|
||||||
<widget class="QTextEdit" name="textEditComment" />
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" >
|
<item row="0" column="0" >
|
||||||
<widget class="QLabel" name="textLabelName" >
|
<widget class="QLabel" name="textLabelName" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
|
@ -56,32 +53,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0" >
|
<item row="0" column="1" >
|
||||||
<spacer>
|
<widget class="QLineEdit" name="lineEditName" >
|
||||||
<property name="orientation" >
|
<property name="minimumSize" >
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType" >
|
|
||||||
<enum>QSizePolicy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" >
|
|
||||||
<size>
|
<size>
|
||||||
<width>91</width>
|
<width>0</width>
|
||||||
<height>240</height>
|
<height>25</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="readOnly" >
|
||||||
</item>
|
<bool>true</bool>
|
||||||
<item row="7" column="0" >
|
|
||||||
<widget class="QLabel" name="textLabelComment" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Commen&t:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment" >
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="buddy" >
|
|
||||||
<cstring>textEditComment</cstring>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -108,40 +89,30 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1" >
|
<item row="2" column="0" >
|
||||||
<widget class="QLineEdit" name="lineEditCreator" >
|
<widget class="QLabel" name="textLabelUuid" >
|
||||||
<property name="minimumSize" >
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>25</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1" >
|
|
||||||
<widget class="QLineEdit" name="lineEditLastMod" >
|
|
||||||
<property name="minimumSize" >
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>25</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" >
|
|
||||||
<widget class="QLabel" name="textLabelLastMod" >
|
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>&Last modified by:</string>
|
<string>UUID:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment" >
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy" >
|
</widget>
|
||||||
<cstring>lineEditLastMod</cstring>
|
</item>
|
||||||
|
<item row="2" column="1" >
|
||||||
|
<widget class="QLineEdit" name="lineEditUuid" >
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly" >
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" >
|
<item row="3" column="0" >
|
||||||
<widget class="QLabel" name="textLabelCreator" >
|
<widget class="QLabel" name="textLabelCreator" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Created &by:</string>
|
<string>Created &by:</string>
|
||||||
|
@ -154,20 +125,66 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0" >
|
<item row="3" column="1" >
|
||||||
<widget class="QLabel" name="textLabelCompany" >
|
<widget class="QLineEdit" name="lineEditCreator" >
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" >
|
||||||
|
<widget class="QLabel" name="textLabelCreateDate" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Com&pany:</string>
|
<string>Creation &date:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment" >
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy" >
|
<property name="buddy" >
|
||||||
<cstring>lineEditCompany</cstring>
|
<cstring>lineEditDate</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1" >
|
||||||
|
<widget class="QLineEdit" name="lineEditDate" >
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly" >
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0" >
|
<item row="5" column="0" >
|
||||||
|
<widget class="QLabel" name="textLabelLastMod" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Last modified by:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" >
|
||||||
|
<cstring>lineEditLastMod</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1" >
|
||||||
|
<widget class="QLineEdit" name="lineEditLastMod" >
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>25</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0" >
|
||||||
<widget class="QLabel" name="textLabelLastModDate" >
|
<widget class="QLabel" name="textLabelLastModDate" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Last &modification date:</string>
|
<string>Last &modification date:</string>
|
||||||
|
@ -181,29 +198,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1" >
|
<item row="6" column="1" >
|
||||||
<widget class="QLineEdit" name="lineEditCompany" >
|
|
||||||
<property name="minimumSize" >
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>25</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1" >
|
|
||||||
<widget class="QLineEdit" name="lineEditDate" >
|
|
||||||
<property name="minimumSize" >
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>25</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="1" >
|
|
||||||
<widget class="QLineEdit" name="lineEditLastModDate" >
|
<widget class="QLineEdit" name="lineEditLastModDate" >
|
||||||
<property name="minimumSize" >
|
<property name="minimumSize" >
|
||||||
<size>
|
<size>
|
||||||
|
@ -216,32 +210,61 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" >
|
<item row="7" column="0" >
|
||||||
<widget class="QLabel" name="textLabelCreateDate" >
|
<widget class="QLabel" name="textLabelCompany" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Creation &date:</string>
|
<string>Com&pany:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment" >
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy" >
|
<property name="buddy" >
|
||||||
<cstring>lineEditDate</cstring>
|
<cstring>lineEditCompany</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1" >
|
<item row="7" column="1" >
|
||||||
<widget class="QLineEdit" name="lineEditName" >
|
<widget class="QLineEdit" name="lineEditCompany" >
|
||||||
<property name="minimumSize" >
|
<property name="minimumSize" >
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>0</width>
|
||||||
<height>25</height>
|
<height>25</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="readOnly" >
|
</widget>
|
||||||
<bool>true</bool>
|
</item>
|
||||||
|
<item row="8" column="0" >
|
||||||
|
<widget class="QLabel" name="textLabelComment" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Commen&t:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" >
|
||||||
|
<cstring>textEditComment</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item rowspan="2" row="8" column="1" >
|
||||||
|
<widget class="QTextEdit" name="textEditComment" />
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0" >
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType" >
|
||||||
|
<enum>QSizePolicy::Expanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>91</width>
|
||||||
|
<height>240</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -304,14 +327,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11" />
|
<layoutdefault spacing="6" margin="11" />
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>lineEditName</tabstop>
|
|
||||||
<tabstop>lineEditCreator</tabstop>
|
|
||||||
<tabstop>lineEditDate</tabstop>
|
|
||||||
<tabstop>lineEditLastMod</tabstop>
|
|
||||||
<tabstop>lineEditLastModDate</tabstop>
|
|
||||||
<tabstop>lineEditCompany</tabstop>
|
|
||||||
<tabstop>buttonOk</tabstop>
|
|
||||||
<tabstop>buttonCancel</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
|
|
|
@ -46,6 +46,7 @@ DlgProjectInformationImp::DlgProjectInformationImp( App::Document* doc, QWidget*
|
||||||
this->setupUi(this);
|
this->setupUi(this);
|
||||||
lineEditName->setText(QString::fromUtf8(doc->Label.getValue()));
|
lineEditName->setText(QString::fromUtf8(doc->Label.getValue()));
|
||||||
lineEditPath->setText(QString::fromUtf8(doc->FileName.getValue()));
|
lineEditPath->setText(QString::fromUtf8(doc->FileName.getValue()));
|
||||||
|
lineEditUuid->setText(QString::fromUtf8(doc->Uid.getValueStr().c_str()));
|
||||||
lineEditCreator->setText(QString::fromUtf8(doc->CreatedBy.getValue()));
|
lineEditCreator->setText(QString::fromUtf8(doc->CreatedBy.getValue()));
|
||||||
lineEditDate->setText(QString::fromUtf8(doc->CreationDate.getValue()));
|
lineEditDate->setText(QString::fromUtf8(doc->CreationDate.getValue()));
|
||||||
lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue()));
|
lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue()));
|
||||||
|
|
|
@ -71,6 +71,7 @@ void DlgSettingsViewColor::saveSettings()
|
||||||
EditedVertexColor->onSave();
|
EditedVertexColor->onSave();
|
||||||
ConstructionColor->onSave();
|
ConstructionColor->onSave();
|
||||||
FullyConstrainedColor->onSave();
|
FullyConstrainedColor->onSave();
|
||||||
|
BoundingBoxColor->onSave();
|
||||||
DefaultShapeColor->onSave();
|
DefaultShapeColor->onSave();
|
||||||
DefaultShapeLineColor->onSave();
|
DefaultShapeLineColor->onSave();
|
||||||
DefaultShapeLineWidth->onSave();
|
DefaultShapeLineWidth->onSave();
|
||||||
|
@ -94,6 +95,7 @@ void DlgSettingsViewColor::loadSettings()
|
||||||
EditedVertexColor->onRestore();
|
EditedVertexColor->onRestore();
|
||||||
ConstructionColor->onRestore();
|
ConstructionColor->onRestore();
|
||||||
FullyConstrainedColor->onRestore();
|
FullyConstrainedColor->onRestore();
|
||||||
|
BoundingBoxColor->onRestore();
|
||||||
DefaultShapeColor->onRestore();
|
DefaultShapeColor->onRestore();
|
||||||
DefaultShapeLineColor->onRestore();
|
DefaultShapeLineColor->onRestore();
|
||||||
DefaultShapeLineWidth->onRestore();
|
DefaultShapeLineWidth->onRestore();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>601</width>
|
<width>601</width>
|
||||||
<height>565</height>
|
<height>598</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -520,6 +520,33 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Bounding box color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="Gui::PrefColorButton" name="BoundingBoxColor">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The color of bounding boxes in the 3D view</string>
|
||||||
|
</property>
|
||||||
|
<property name="color">
|
||||||
|
<color>
|
||||||
|
<red>255</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>255</blue>
|
||||||
|
</color>
|
||||||
|
</property>
|
||||||
|
<property name="prefEntry" stdset="0">
|
||||||
|
<cstring>BoundingBoxColor</cstring>
|
||||||
|
</property>
|
||||||
|
<property name="prefPath" stdset="0">
|
||||||
|
<cstring>View</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
@ -660,6 +687,7 @@
|
||||||
<tabstop>EditedVertexColor</tabstop>
|
<tabstop>EditedVertexColor</tabstop>
|
||||||
<tabstop>ConstructionColor</tabstop>
|
<tabstop>ConstructionColor</tabstop>
|
||||||
<tabstop>FullyConstrainedColor</tabstop>
|
<tabstop>FullyConstrainedColor</tabstop>
|
||||||
|
<tabstop>BoundingBoxColor</tabstop>
|
||||||
<tabstop>radioButtonSimple</tabstop>
|
<tabstop>radioButtonSimple</tabstop>
|
||||||
<tabstop>SelectionColor_Background</tabstop>
|
<tabstop>SelectionColor_Background</tabstop>
|
||||||
<tabstop>radioButtonGradient</tabstop>
|
<tabstop>radioButtonGradient</tabstop>
|
||||||
|
|
|
@ -288,7 +288,11 @@ void DlgCustomToolbars::on_moveActionRightButton_clicked()
|
||||||
QTreeWidgetItem* item = commandTreeWidget->currentItem();
|
QTreeWidgetItem* item = commandTreeWidget->currentItem();
|
||||||
if (item) {
|
if (item) {
|
||||||
QTreeWidgetItem* current = toolbarTreeWidget->currentItem();
|
QTreeWidgetItem* current = toolbarTreeWidget->currentItem();
|
||||||
if (current && !current->parent() && toolbarTreeWidget->isItemSelected(current)) {
|
if (!current)
|
||||||
|
current = toolbarTreeWidget->topLevelItem(0);
|
||||||
|
else if (current->parent())
|
||||||
|
current = current->parent();
|
||||||
|
if (current && !current->parent()) {
|
||||||
QTreeWidgetItem* copy = new QTreeWidgetItem(current);
|
QTreeWidgetItem* copy = new QTreeWidgetItem(current);
|
||||||
copy->setText(0, item->text(1));
|
copy->setText(0, item->text(1));
|
||||||
copy->setIcon(0, item->icon(0));
|
copy->setIcon(0, item->icon(0));
|
||||||
|
|
|
@ -571,43 +571,18 @@ bool Document::saveAs(void)
|
||||||
getMainWindow()->showMessage(QObject::tr("Save document under new filename..."));
|
getMainWindow()->showMessage(QObject::tr("Save document under new filename..."));
|
||||||
|
|
||||||
QString exe = qApp->applicationName();
|
QString exe = qApp->applicationName();
|
||||||
QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe),
|
QString fn = FileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe),
|
||||||
FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.FCStd)").arg(exe));
|
QString(), QObject::tr("%1 document (*.FCStd)").arg(exe));
|
||||||
if (!fn.isEmpty()) {
|
|
||||||
FileDialog::setWorkingDirectory(fn);
|
|
||||||
QString file = fn.toLower();
|
|
||||||
if (!file.endsWith(QLatin1String(".fcstd"))) {
|
|
||||||
fn += QLatin1String(".fcstd");
|
|
||||||
QFileInfo fi;
|
|
||||||
fi.setFile(fn);
|
|
||||||
if (fi.exists()) {
|
|
||||||
// if we auto-append the extension make sure that we don't override an existing file
|
|
||||||
int ret = QMessageBox::question(getMainWindow(), QObject::tr("Save As"),
|
|
||||||
QObject::tr("%1 already exists.\n"
|
|
||||||
"Do you want to replace it?").arg(fn),
|
|
||||||
QMessageBox::Yes|QMessageBox::Default,
|
|
||||||
QMessageBox::No|QMessageBox::Escape);
|
|
||||||
if (ret != QMessageBox::Yes)
|
|
||||||
fn = QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fn.isEmpty()) {
|
if (!fn.isEmpty()) {
|
||||||
QFileInfo fi;
|
QFileInfo fi;
|
||||||
fi.setFile(fn);
|
fi.setFile(fn);
|
||||||
QString bn = fi.baseName();
|
|
||||||
|
|
||||||
const char * DocName = App::GetApplication().getDocumentName(getDocument());
|
const char * DocName = App::GetApplication().getDocumentName(getDocument());
|
||||||
|
|
||||||
// save as new file name
|
// save as new file name
|
||||||
Gui::WaitCursor wc;
|
Gui::WaitCursor wc;
|
||||||
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").FileName = \"%s\""
|
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").saveAs('%s')"
|
||||||
, DocName, (const char*)fn.toUtf8());
|
, DocName, (const char*)fn.toUtf8());
|
||||||
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").Label = \"%s\""
|
|
||||||
, DocName, (const char*)bn.toUtf8());
|
|
||||||
Command::doCommand(Command::Doc,"App.getDocument(\"%s\").save()"
|
|
||||||
, DocName);
|
|
||||||
setModified(false);
|
setModified(false);
|
||||||
|
|
||||||
getMainWindow()->appendRecentFile(fi.filePath());
|
getMainWindow()->appendRecentFile(fi.filePath());
|
||||||
|
@ -695,9 +670,20 @@ void Document::RestoreDocFile(Base::Reader &reader)
|
||||||
for (i=0 ;i<Cnt ;i++) {
|
for (i=0 ;i<Cnt ;i++) {
|
||||||
xmlReader.readElement("ViewProvider");
|
xmlReader.readElement("ViewProvider");
|
||||||
std::string name = xmlReader.getAttribute("name");
|
std::string name = xmlReader.getAttribute("name");
|
||||||
|
bool expanded = false;
|
||||||
|
if (xmlReader.hasAttribute("expanded")) {
|
||||||
|
const char* attr = xmlReader.getAttribute("expanded");
|
||||||
|
if (strcmp(attr,"1") == 0) {
|
||||||
|
expanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
ViewProvider* pObj = getViewProviderByName(name.c_str());
|
ViewProvider* pObj = getViewProviderByName(name.c_str());
|
||||||
if (pObj) // check if this feature has been registered
|
if (pObj) // check if this feature has been registered
|
||||||
pObj->Restore(xmlReader);
|
pObj->Restore(xmlReader);
|
||||||
|
if (expanded) {
|
||||||
|
Gui::ViewProviderDocumentObject* vp = static_cast<Gui::ViewProviderDocumentObject*>(pObj);
|
||||||
|
this->signalExpandObject(*vp, Gui::Expand);
|
||||||
|
}
|
||||||
xmlReader.readEndElement("ViewProvider");
|
xmlReader.readEndElement("ViewProvider");
|
||||||
}
|
}
|
||||||
xmlReader.readEndElement("ViewProviderData");
|
xmlReader.readEndElement("ViewProviderData");
|
||||||
|
@ -784,7 +770,9 @@ void Document::SaveDocFile (Base::Writer &writer) const
|
||||||
const App::DocumentObject* doc = it->first;
|
const App::DocumentObject* doc = it->first;
|
||||||
ViewProvider* obj = it->second;
|
ViewProvider* obj = it->second;
|
||||||
writer.Stream() << writer.ind() << "<ViewProvider name=\""
|
writer.Stream() << writer.ind() << "<ViewProvider name=\""
|
||||||
<< doc->getNameInDocument() << "\">" << std::endl;
|
<< doc->getNameInDocument() << "\" "
|
||||||
|
<< "expanded=\"" << (doc->testStatus(App::Expand) ? 1:0)
|
||||||
|
<< "\">" << std::endl;
|
||||||
obj->Save(writer);
|
obj->Save(writer);
|
||||||
writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
|
writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
# include <boost/bind.hpp>
|
# include <boost/bind.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
#include "DocumentModel.h"
|
#include "DocumentModel.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BitmapFactory.h"
|
#include "BitmapFactory.h"
|
||||||
|
@ -54,8 +56,6 @@ namespace Gui {
|
||||||
virtual ~DocumentModelIndex()
|
virtual ~DocumentModelIndex()
|
||||||
{ qDeleteAll(childItems); }
|
{ qDeleteAll(childItems); }
|
||||||
|
|
||||||
void reset()
|
|
||||||
{ qDeleteAll(childItems); childItems.clear(); }
|
|
||||||
void setParent(DocumentModelIndex* parent)
|
void setParent(DocumentModelIndex* parent)
|
||||||
{ parentItem = parent; }
|
{ parentItem = parent; }
|
||||||
DocumentModelIndex *parent() const
|
DocumentModelIndex *parent() const
|
||||||
|
@ -64,7 +64,12 @@ namespace Gui {
|
||||||
{ childItems.append(child); child->setParent(this); }
|
{ childItems.append(child); child->setParent(this); }
|
||||||
void removeChild(int row)
|
void removeChild(int row)
|
||||||
{ childItems.removeAt(row); }
|
{ childItems.removeAt(row); }
|
||||||
|
QList<DocumentModelIndex*> removeAll()
|
||||||
|
{
|
||||||
|
QList<DocumentModelIndex*> list = childItems;
|
||||||
|
childItems.clear();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
DocumentModelIndex *child(int row)
|
DocumentModelIndex *child(int row)
|
||||||
{ return childItems.value(row); }
|
{ return childItems.value(row); }
|
||||||
int row() const
|
int row() const
|
||||||
|
@ -91,11 +96,18 @@ namespace Gui {
|
||||||
return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void reset()
|
||||||
|
{ qDeleteAll(childItems); childItems.clear(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DocumentModelIndex() : parentItem(0) {}
|
DocumentModelIndex() : parentItem(0) {}
|
||||||
DocumentModelIndex *parentItem;
|
DocumentModelIndex *parentItem;
|
||||||
QList<DocumentModelIndex*> childItems;
|
QList<DocumentModelIndex*> childItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
// Root node
|
// Root node
|
||||||
class ApplicationIndex : public DocumentModelIndex
|
class ApplicationIndex : public DocumentModelIndex
|
||||||
{
|
{
|
||||||
|
@ -104,9 +116,80 @@ namespace Gui {
|
||||||
public:
|
public:
|
||||||
ApplicationIndex(){}
|
ApplicationIndex(){}
|
||||||
int findChild(const Gui::Document& d) const;
|
int findChild(const Gui::Document& d) const;
|
||||||
Qt::ItemFlags flags() const
|
Qt::ItemFlags flags() const;
|
||||||
{ return Qt::ItemIsEnabled; }
|
QVariant data(int role) const;
|
||||||
QVariant data(int role) const
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Document nodes
|
||||||
|
class DocumentIndex : public DocumentModelIndex
|
||||||
|
{
|
||||||
|
friend class ViewProviderIndex;
|
||||||
|
TYPESYSTEM_HEADER();
|
||||||
|
static QIcon* documentIcon;
|
||||||
|
typedef boost::unordered_set<ViewProviderIndex*> IndexSet;
|
||||||
|
std::map<const ViewProviderDocumentObject*, IndexSet> vp_nodes;
|
||||||
|
void addToDocument(ViewProviderIndex*);
|
||||||
|
void removeFromDocument(ViewProviderIndex*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Gui::Document& d;
|
||||||
|
DocumentIndex(const Gui::Document& d) : d(d)
|
||||||
|
{
|
||||||
|
if (!documentIcon)
|
||||||
|
documentIcon = new QIcon(Gui::BitmapFactory().pixmap("Document"));
|
||||||
|
}
|
||||||
|
~DocumentIndex()
|
||||||
|
{
|
||||||
|
qDeleteAll(childItems); childItems.clear();
|
||||||
|
}
|
||||||
|
ViewProviderIndex* cloneViewProvider(const ViewProviderDocumentObject&) const;
|
||||||
|
int rowOfViewProvider(const ViewProviderDocumentObject&) const;
|
||||||
|
void findViewProviders(const ViewProviderDocumentObject&, QList<ViewProviderIndex*>&) const;
|
||||||
|
QVariant data(int role) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Object nodes
|
||||||
|
class ViewProviderIndex : public DocumentModelIndex
|
||||||
|
{
|
||||||
|
TYPESYSTEM_HEADER();
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Gui::ViewProviderDocumentObject& v;
|
||||||
|
ViewProviderIndex(const Gui::ViewProviderDocumentObject& v, DocumentIndex* d);
|
||||||
|
~ViewProviderIndex();
|
||||||
|
ViewProviderIndex* clone() const;
|
||||||
|
void findViewProviders(const ViewProviderDocumentObject&, QList<ViewProviderIndex*>&) const;
|
||||||
|
QVariant data(int role) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocumentIndex* d;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ApplicationIndex::findChild(const Gui::Document& d) const
|
||||||
|
{
|
||||||
|
int child=0;
|
||||||
|
QList<DocumentModelIndex*>::const_iterator it;
|
||||||
|
for (it = childItems.begin(); it != childItems.end(); ++it, ++child) {
|
||||||
|
DocumentIndex* doc = static_cast<DocumentIndex*>(*it);
|
||||||
|
if (&doc->d == &d)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags ApplicationIndex::flags() const
|
||||||
|
{
|
||||||
|
return Qt::ItemIsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ApplicationIndex::data(int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DecorationRole) {
|
if (role == Qt::DecorationRole) {
|
||||||
return qApp->windowIcon();
|
return qApp->windowIcon();
|
||||||
|
@ -116,23 +199,58 @@ namespace Gui {
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// Document nodes
|
|
||||||
class DocumentIndex : public DocumentModelIndex
|
|
||||||
{
|
|
||||||
TYPESYSTEM_HEADER();
|
|
||||||
static QIcon* documentIcon;
|
|
||||||
|
|
||||||
public:
|
// ------------------------------------------------------------------------
|
||||||
const Gui::Document& d;
|
|
||||||
DocumentIndex(const Gui::Document& d) : d(d)
|
QIcon* DocumentIndex::documentIcon = 0;
|
||||||
|
|
||||||
|
void DocumentIndex::addToDocument(ViewProviderIndex* vp)
|
||||||
{
|
{
|
||||||
if (!documentIcon)
|
vp_nodes[&vp->v].insert(vp);
|
||||||
documentIcon = new QIcon(Gui::BitmapFactory().pixmap("Document"));
|
|
||||||
}
|
}
|
||||||
int findViewProvider(const ViewProvider&) const;
|
|
||||||
void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
|
void DocumentIndex::removeFromDocument(ViewProviderIndex* vp)
|
||||||
QVariant data(int role) const
|
{
|
||||||
|
vp_nodes[&vp->v].erase(vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewProviderIndex*
|
||||||
|
DocumentIndex::cloneViewProvider(const ViewProviderDocumentObject& vp) const
|
||||||
|
{
|
||||||
|
std::map<const ViewProviderDocumentObject*, boost::unordered_set<ViewProviderIndex*> >::const_iterator it;
|
||||||
|
it = vp_nodes.find(&vp);
|
||||||
|
if (it != vp_nodes.end()) {
|
||||||
|
boost::unordered_set<ViewProviderIndex*>::const_iterator v;
|
||||||
|
v = it->second.begin();
|
||||||
|
return (*v)->clone();
|
||||||
|
}
|
||||||
|
return new ViewProviderIndex(vp, const_cast<DocumentIndex*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentIndex::findViewProviders(const ViewProviderDocumentObject& vp,
|
||||||
|
QList<ViewProviderIndex*>& index) const
|
||||||
|
{
|
||||||
|
QList<DocumentModelIndex*>::const_iterator it;
|
||||||
|
for (it = childItems.begin(); it != childItems.end(); ++it) {
|
||||||
|
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
||||||
|
v->findViewProviders(vp, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DocumentIndex::rowOfViewProvider(const ViewProviderDocumentObject& vp) const
|
||||||
|
{
|
||||||
|
QList<DocumentModelIndex*>::const_iterator it;
|
||||||
|
int index=0;
|
||||||
|
for (it = childItems.begin(); it != childItems.end(); ++it, ++index) {
|
||||||
|
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
||||||
|
if (&v->v == &vp)
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DocumentIndex::data(int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DecorationRole) {
|
if (role == Qt::DecorationRole) {
|
||||||
return *documentIcon;
|
return *documentIcon;
|
||||||
|
@ -152,18 +270,43 @@ namespace Gui {
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Object nodes
|
// ------------------------------------------------------------------------
|
||||||
class ViewProviderIndex : public DocumentModelIndex
|
|
||||||
|
ViewProviderIndex::ViewProviderIndex(const Gui::ViewProviderDocumentObject& v, DocumentIndex* d)
|
||||||
|
: v(v),d(d)
|
||||||
{
|
{
|
||||||
TYPESYSTEM_HEADER();
|
if (d) d->addToDocument(this);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
ViewProviderIndex::~ViewProviderIndex()
|
||||||
const Gui::ViewProviderDocumentObject& v;
|
{
|
||||||
ViewProviderIndex(const Gui::ViewProviderDocumentObject& v) : v(v){}
|
if (d) d->removeFromDocument(this);
|
||||||
void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
|
}
|
||||||
QVariant data(int role) const
|
|
||||||
|
ViewProviderIndex* ViewProviderIndex::clone() const
|
||||||
|
{
|
||||||
|
ViewProviderIndex* copy = new ViewProviderIndex(this->v, this->d);
|
||||||
|
for (QList<DocumentModelIndex*>::const_iterator it = childItems.begin(); it != childItems.end(); ++it) {
|
||||||
|
ViewProviderIndex* c = static_cast<ViewProviderIndex*>(*it)->clone();
|
||||||
|
copy->appendChild(c);
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewProviderIndex::findViewProviders(const ViewProviderDocumentObject& vp,
|
||||||
|
QList<ViewProviderIndex*>& index) const
|
||||||
|
{
|
||||||
|
if (&this->v == &vp)
|
||||||
|
index.push_back(const_cast<ViewProviderIndex*>(this));
|
||||||
|
QList<DocumentModelIndex*>::const_iterator it;
|
||||||
|
for (it = childItems.begin(); it != childItems.end(); ++it) {
|
||||||
|
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
||||||
|
v->findViewProviders(vp, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ViewProviderIndex::data(int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DecorationRole) {
|
if (role == Qt::DecorationRole) {
|
||||||
return v.getIcon();
|
return v.getIcon();
|
||||||
|
@ -184,57 +327,8 @@ namespace Gui {
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
int ApplicationIndex::findChild(const Gui::Document& d) const
|
// ------------------------------------------------------------------------
|
||||||
{
|
|
||||||
int child=0;
|
|
||||||
QList<DocumentModelIndex*>::const_iterator it;
|
|
||||||
for (it = childItems.begin(); it != childItems.end(); ++it, ++child) {
|
|
||||||
DocumentIndex* doc = static_cast<DocumentIndex*>(*it);
|
|
||||||
if (&doc->d == &d)
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon* DocumentIndex::documentIcon = 0;
|
|
||||||
|
|
||||||
void DocumentIndex::findViewProviders(const ViewProvider& vp,
|
|
||||||
QList<ViewProviderIndex*>& index) const
|
|
||||||
{
|
|
||||||
QList<DocumentModelIndex*>::const_iterator it;
|
|
||||||
for (it = childItems.begin(); it != childItems.end(); ++it) {
|
|
||||||
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
|
||||||
v->findViewProviders(vp, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int DocumentIndex::findViewProvider(const ViewProvider& vp) const
|
|
||||||
{
|
|
||||||
QList<DocumentModelIndex*>::const_iterator it;
|
|
||||||
int index=0;
|
|
||||||
for (it = childItems.begin(); it != childItems.end(); ++it, ++index) {
|
|
||||||
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
|
||||||
if (&v->v == &vp)
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewProviderIndex::findViewProviders(const ViewProvider& vp,
|
|
||||||
QList<ViewProviderIndex*>& index) const
|
|
||||||
{
|
|
||||||
if (&this->v == &vp)
|
|
||||||
index.push_back(const_cast<ViewProviderIndex*>(this));
|
|
||||||
QList<DocumentModelIndex*>::const_iterator it;
|
|
||||||
for (it = childItems.begin(); it != childItems.end(); ++it) {
|
|
||||||
ViewProviderIndex* v = static_cast<ViewProviderIndex*>(*it);
|
|
||||||
v->findViewProviders(vp, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentModelIndex, Base::BaseClass);
|
TYPESYSTEM_SOURCE_ABSTRACT(Gui::DocumentModelIndex, Base::BaseClass);
|
||||||
TYPESYSTEM_SOURCE_ABSTRACT(Gui::ApplicationIndex,Gui::DocumentModelIndex);
|
TYPESYSTEM_SOURCE_ABSTRACT(Gui::ApplicationIndex,Gui::DocumentModelIndex);
|
||||||
|
@ -350,7 +444,7 @@ void DocumentModel::slotNewObject(const Gui::ViewProviderDocumentObject& obj)
|
||||||
QModelIndex parent = createIndex(index->row(),0,index);
|
QModelIndex parent = createIndex(index->row(),0,index);
|
||||||
int count_obj = index->childCount();
|
int count_obj = index->childCount();
|
||||||
beginInsertRows(parent, count_obj, count_obj);
|
beginInsertRows(parent, count_obj, count_obj);
|
||||||
index->appendChild(new ViewProviderIndex(obj));
|
index->appendChild(new ViewProviderIndex(obj, index));
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,35 +493,47 @@ void DocumentModel::slotChangeObject(const Gui::ViewProviderDocumentObject& obj,
|
||||||
else if (isPropertyLink(Prop)) {
|
else if (isPropertyLink(Prop)) {
|
||||||
App::Document* doc = fea->getDocument();
|
App::Document* doc = fea->getDocument();
|
||||||
Gui::Document* gdc = Application::Instance->getDocument(doc);
|
Gui::Document* gdc = Application::Instance->getDocument(doc);
|
||||||
std::vector<ViewProviderDocumentObject*> views = getLinkedObjects(*gdc, Prop);
|
std::vector<ViewProviderDocumentObject*> views = claimChildren(*gdc, obj);
|
||||||
|
|
||||||
int row = d->rootItem->findChild(*gdc);
|
int row = d->rootItem->findChild(*gdc);
|
||||||
if (row > -1) {
|
if (row > -1) {
|
||||||
|
QList<DocumentModelIndex*> del_items;
|
||||||
DocumentIndex* doc_index = static_cast<DocumentIndex*>(d->rootItem->child(row));
|
DocumentIndex* doc_index = static_cast<DocumentIndex*>(d->rootItem->child(row));
|
||||||
QList<ViewProviderIndex*> obj_index;
|
|
||||||
doc_index->findViewProviders(obj, obj_index);
|
|
||||||
|
|
||||||
// remove from top level in document
|
|
||||||
for (std::vector<ViewProviderDocumentObject*>::iterator vp = views.begin(); vp != views.end(); ++vp) {
|
for (std::vector<ViewProviderDocumentObject*>::iterator vp = views.begin(); vp != views.end(); ++vp) {
|
||||||
int row = doc_index->findViewProvider(**vp);
|
int row = doc_index->rowOfViewProvider(**vp);
|
||||||
|
// is it a top-level child in the document
|
||||||
if (row >= 0) {
|
if (row >= 0) {
|
||||||
DocumentModelIndex* child = doc_index->child(row);
|
DocumentModelIndex* child = doc_index->child(row);
|
||||||
|
del_items.push_back(child);
|
||||||
QModelIndex parent = createIndex(doc_index->row(), 0, doc_index);
|
QModelIndex parent = createIndex(doc_index->row(), 0, doc_index);
|
||||||
beginRemoveRows(parent, row, row);
|
beginRemoveRows(parent, row, row);
|
||||||
doc_index->removeChild(row);
|
doc_index->removeChild(row);
|
||||||
delete child;
|
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get all occurrences of the view provider in the tree structure
|
||||||
|
QList<ViewProviderIndex*> obj_index;
|
||||||
|
doc_index->findViewProviders(obj, obj_index);
|
||||||
for (QList<ViewProviderIndex*>::iterator it = obj_index.begin(); it != obj_index.end(); ++it) {
|
for (QList<ViewProviderIndex*>::iterator it = obj_index.begin(); it != obj_index.end(); ++it) {
|
||||||
QModelIndex parent = createIndex((*it)->row(),0,*it);
|
QModelIndex parent = createIndex((*it)->row(),0,*it);
|
||||||
int count_obj = (*it)->childCount();
|
int count_obj = (*it)->childCount();
|
||||||
beginInsertRows(parent, count_obj, count_obj + (int)views.size());
|
beginRemoveRows(parent, 0, count_obj);
|
||||||
for (std::vector<ViewProviderDocumentObject*>::iterator jt = views.begin(); jt != views.end(); ++jt)
|
// remove all children but do not yet delete them
|
||||||
(*it)->appendChild(new ViewProviderIndex(**jt));
|
QList<DocumentModelIndex*> items = (*it)->removeAll();
|
||||||
endInsertRows();
|
endRemoveRows();
|
||||||
|
|
||||||
|
beginInsertRows(parent, 0, (int)views.size());
|
||||||
|
for (std::vector<ViewProviderDocumentObject*>::iterator vp = views.begin(); vp != views.end(); ++vp) {
|
||||||
|
ViewProviderIndex* clone = doc_index->cloneViewProvider(**vp);
|
||||||
|
(*it)->appendChild(clone);
|
||||||
}
|
}
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
del_items.append(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDeleteAll(del_items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,33 +567,27 @@ bool DocumentModel::isPropertyLink(const App::Property& prop) const
|
||||||
{
|
{
|
||||||
if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId()))
|
if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId()))
|
||||||
return true;
|
return true;
|
||||||
|
if (prop.isDerivedFrom(App::PropertyLinkSub::getClassTypeId()))
|
||||||
|
return true;
|
||||||
if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId()))
|
if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId()))
|
||||||
return true;
|
return true;
|
||||||
|
if (prop.isDerivedFrom(App::PropertyLinkSubList::getClassTypeId()))
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ViewProviderDocumentObject*>
|
std::vector<ViewProviderDocumentObject*>
|
||||||
DocumentModel::getLinkedObjects(const Gui::Document& doc, const App::Property& prop) const
|
DocumentModel::claimChildren(const Gui::Document& doc, const ViewProviderDocumentObject& obj) const
|
||||||
{
|
{
|
||||||
std::vector<ViewProviderDocumentObject*> links;
|
std::vector<ViewProviderDocumentObject*> views;
|
||||||
if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId())) {
|
std::vector<App::DocumentObject*> childs = obj.claimChildren();
|
||||||
App::DocumentObject* obj;
|
for (std::vector<App::DocumentObject*>::iterator it = childs.begin(); it != childs.end(); ++it) {
|
||||||
obj = static_cast<const App::PropertyLink&>(prop).getValue();
|
|
||||||
ViewProvider* view = doc.getViewProvider(obj);
|
|
||||||
if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
|
|
||||||
links.push_back(static_cast<ViewProviderDocumentObject*>(view));
|
|
||||||
}
|
|
||||||
else if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId())) {
|
|
||||||
const std::vector<App::DocumentObject*>& refs = static_cast
|
|
||||||
<const App::PropertyLinkList&>(prop).getValues();
|
|
||||||
for (std::vector<App::DocumentObject*>::const_iterator it = refs.begin();it != refs.end(); ++it) {
|
|
||||||
ViewProvider* view = doc.getViewProvider(*it);
|
ViewProvider* view = doc.getViewProvider(*it);
|
||||||
if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
|
if (view && view->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
|
||||||
links.push_back(static_cast<ViewProviderDocumentObject*>(view));
|
views.push_back(static_cast<ViewProviderDocumentObject*>(view));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return links;
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DocumentModel::columnCount (const QModelIndex & /*parent*/) const
|
int DocumentModel::columnCount (const QModelIndex & /*parent*/) const
|
||||||
|
|
|
@ -67,8 +67,8 @@ private:
|
||||||
|
|
||||||
const Document* getDocument(const QModelIndex&) const;
|
const Document* getDocument(const QModelIndex&) const;
|
||||||
bool isPropertyLink(const App::Property&) const;
|
bool isPropertyLink(const App::Property&) const;
|
||||||
std::vector<ViewProviderDocumentObject*> getLinkedObjects
|
std::vector<ViewProviderDocumentObject*> claimChildren
|
||||||
(const Gui::Document&, const App::Property&) const;
|
(const Document&, const ViewProviderDocumentObject&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct DocumentModelP *d;
|
struct DocumentModelP *d;
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
# include <QHBoxLayout>
|
# include <QHBoxLayout>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QAuthenticator>
|
||||||
#include "DownloadDialog.h"
|
#include "DownloadDialog.h"
|
||||||
|
#include "ui_DlgAuthorization.h"
|
||||||
|
|
||||||
using namespace Gui::Dialog;
|
using namespace Gui::Dialog;
|
||||||
|
|
||||||
|
@ -202,6 +204,16 @@ void DownloadDialog::updateDataReadProgress(int bytesRead, int totalBytes)
|
||||||
|
|
||||||
void DownloadDialog::slotAuthenticationRequired(const QString &hostName, quint16, QAuthenticator *authenticator)
|
void DownloadDialog::slotAuthenticationRequired(const QString &hostName, quint16, QAuthenticator *authenticator)
|
||||||
{
|
{
|
||||||
|
QDialog dlg;
|
||||||
|
Ui_DlgAuthorization ui;
|
||||||
|
ui.setupUi(&dlg);
|
||||||
|
dlg.adjustSize();
|
||||||
|
ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm()).arg(hostName));
|
||||||
|
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
authenticator->setUser(ui.username->text());
|
||||||
|
authenticator->setPassword(ui.password->text());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
583
src/Gui/DownloadItem.cpp
Normal file
583
src/Gui/DownloadItem.cpp
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "PreCompiled.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <QAuthenticator>
|
||||||
|
#include <QContextMenuEvent>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QNetworkDiskCache>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkProxy>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
#include <App/Document.h>
|
||||||
|
|
||||||
|
#include "DownloadItem.h"
|
||||||
|
#include "DownloadManager.h"
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Document.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "FileDialog.h"
|
||||||
|
#include "ui_DlgAuthorization.h"
|
||||||
|
|
||||||
|
using namespace Gui::Dialog;
|
||||||
|
|
||||||
|
|
||||||
|
EditTableView::EditTableView(QWidget *parent)
|
||||||
|
: QTableView(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTableView::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if ((event->key() == Qt::Key_Delete
|
||||||
|
|| event->key() == Qt::Key_Backspace)
|
||||||
|
&& model()) {
|
||||||
|
removeOne();
|
||||||
|
} else {
|
||||||
|
QAbstractItemView::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTableView::removeOne()
|
||||||
|
{
|
||||||
|
if (!model() || !selectionModel())
|
||||||
|
return;
|
||||||
|
int row = currentIndex().row();
|
||||||
|
model()->removeRow(row, rootIndex());
|
||||||
|
QModelIndex idx = model()->index(row, 0, rootIndex());
|
||||||
|
if (!idx.isValid())
|
||||||
|
idx = model()->index(row - 1, 0, rootIndex());
|
||||||
|
selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditTableView::removeAll()
|
||||||
|
{
|
||||||
|
if (model())
|
||||||
|
model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SqueezeLabel::SqueezeLabel(QWidget *parent) : QLabel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqueezeLabel::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
QFontMetrics fm = fontMetrics();
|
||||||
|
if (fm.width(text()) > contentsRect().width()) {
|
||||||
|
QString elided = fm.elidedText(text(), Qt::ElideMiddle, width());
|
||||||
|
QString oldText = text();
|
||||||
|
setText(elided);
|
||||||
|
QLabel::paintEvent(event);
|
||||||
|
setText(oldText);
|
||||||
|
} else {
|
||||||
|
QLabel::paintEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define AUTOSAVE_IN 1000 * 3 // seconds
|
||||||
|
#define MAXWAIT 1000 * 15 // seconds
|
||||||
|
|
||||||
|
AutoSaver::AutoSaver(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
Q_ASSERT(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoSaver::~AutoSaver()
|
||||||
|
{
|
||||||
|
if (m_timer.isActive())
|
||||||
|
qWarning() << "AutoSaver: still active when destroyed, changes not saved.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoSaver::changeOccurred()
|
||||||
|
{
|
||||||
|
if (m_firstChange.isNull())
|
||||||
|
m_firstChange.start();
|
||||||
|
|
||||||
|
if (m_firstChange.elapsed() > MAXWAIT) {
|
||||||
|
saveIfNeccessary();
|
||||||
|
} else {
|
||||||
|
m_timer.start(AUTOSAVE_IN, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoSaver::timerEvent(QTimerEvent *event)
|
||||||
|
{
|
||||||
|
if (event->timerId() == m_timer.timerId()) {
|
||||||
|
saveIfNeccessary();
|
||||||
|
} else {
|
||||||
|
QObject::timerEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoSaver::saveIfNeccessary()
|
||||||
|
{
|
||||||
|
if (!m_timer.isActive())
|
||||||
|
return;
|
||||||
|
m_timer.stop();
|
||||||
|
m_firstChange = QTime();
|
||||||
|
if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) {
|
||||||
|
qWarning() << "AutoSaver: error invoking slot save() on parent";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NetworkAccessManager::NetworkAccessManager(QObject *parent)
|
||||||
|
: QNetworkAccessManager(parent)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
|
||||||
|
SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
|
||||||
|
connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
|
||||||
|
SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
|
||||||
|
|
||||||
|
QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
|
||||||
|
QString location = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
|
||||||
|
diskCache->setCacheDirectory(location);
|
||||||
|
setCache(diskCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
|
||||||
|
{
|
||||||
|
QWidget *mainWindow = Gui::getMainWindow();
|
||||||
|
|
||||||
|
QDialog dialog(mainWindow);
|
||||||
|
dialog.setWindowFlags(Qt::Sheet);
|
||||||
|
|
||||||
|
Ui_DlgAuthorization passwordDialog;
|
||||||
|
passwordDialog.setupUi(&dialog);
|
||||||
|
dialog.adjustSize();
|
||||||
|
|
||||||
|
QString introMessage = tr("<qt>Enter username and password for \"%1\" at %2</qt>");
|
||||||
|
introMessage = introMessage.arg(Qt::escape(reply->url().toString())).arg(Qt::escape(reply->url().toString()));
|
||||||
|
passwordDialog.siteDescription->setText(introMessage);
|
||||||
|
passwordDialog.siteDescription->setWordWrap(true);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
auth->setUser(passwordDialog.username->text());
|
||||||
|
auth->setPassword(passwordDialog.password->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
|
||||||
|
{
|
||||||
|
QWidget *mainWindow = Gui::getMainWindow();
|
||||||
|
|
||||||
|
QDialog dialog(mainWindow);
|
||||||
|
dialog.setWindowFlags(Qt::Sheet);
|
||||||
|
|
||||||
|
Ui_DlgAuthorization proxyDialog;
|
||||||
|
proxyDialog.setupUi(&dialog);
|
||||||
|
dialog.adjustSize();
|
||||||
|
|
||||||
|
QString introMessage = tr("<qt>Connect to proxy \"%1\" using:</qt>");
|
||||||
|
introMessage = introMessage.arg(Qt::escape(proxy.hostName()));
|
||||||
|
proxyDialog.siteDescription->setText(introMessage);
|
||||||
|
proxyDialog.siteDescription->setWordWrap(true);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
auth->setUser(proxyDialog.username->text());
|
||||||
|
auth->setPassword(proxyDialog.password->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_reply(reply)
|
||||||
|
, m_requestFileName(requestFileName)
|
||||||
|
, m_bytesReceived(0)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
QPalette p = downloadInfoLabel->palette();
|
||||||
|
p.setColor(QPalette::Text, Qt::darkGray);
|
||||||
|
downloadInfoLabel->setPalette(p);
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
tryAgainButton->hide();
|
||||||
|
connect(stopButton, SIGNAL(clicked()), this, SLOT(stop()));
|
||||||
|
connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
|
||||||
|
connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain()));
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::init()
|
||||||
|
{
|
||||||
|
if (!m_reply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// attach to the m_reply
|
||||||
|
m_url = m_reply->url();
|
||||||
|
m_reply->setParent(this);
|
||||||
|
connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
|
||||||
|
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||||
|
this, SLOT(error(QNetworkReply::NetworkError)));
|
||||||
|
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)),
|
||||||
|
this, SLOT(downloadProgress(qint64, qint64)));
|
||||||
|
connect(m_reply, SIGNAL(metaDataChanged()),
|
||||||
|
this, SLOT(metaDataChanged()));
|
||||||
|
connect(m_reply, SIGNAL(finished()),
|
||||||
|
this, SLOT(finished()));
|
||||||
|
|
||||||
|
// reset info
|
||||||
|
downloadInfoLabel->clear();
|
||||||
|
progressBar->setValue(0);
|
||||||
|
getFileName();
|
||||||
|
|
||||||
|
// start timer for the download estimation
|
||||||
|
m_downloadTime.start();
|
||||||
|
|
||||||
|
if (m_reply->error() != QNetworkReply::NoError) {
|
||||||
|
error(m_reply->error());
|
||||||
|
finished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DownloadItem::getDownloadDirectory() const
|
||||||
|
{
|
||||||
|
QString exe = QString::fromAscii(App::GetApplication().getExecutableName());
|
||||||
|
QString path = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
|
||||||
|
QString dirPath = QDir(path).filePath(exe);
|
||||||
|
Base::Reference<ParameterGrp> hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
|
||||||
|
->GetGroup("Preferences")->GetGroup("General");
|
||||||
|
std::string dir = hPath->GetASCII("DownloadPath", "");
|
||||||
|
if (!dir.empty()) {
|
||||||
|
dirPath = QString::fromUtf8(dir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QFileInfo(dirPath).exists() || QDir().mkpath(dirPath)) {
|
||||||
|
return dirPath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::getFileName()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup(QLatin1String("downloadmanager"));
|
||||||
|
//QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
|
||||||
|
QString defaultLocation = getDownloadDirectory();
|
||||||
|
QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString();
|
||||||
|
if (!downloadDirectory.isEmpty())
|
||||||
|
downloadDirectory += QLatin1Char('/');
|
||||||
|
|
||||||
|
QString defaultFileName = saveFileName(downloadDirectory);
|
||||||
|
QString fileName = defaultFileName;
|
||||||
|
if (m_requestFileName) {
|
||||||
|
fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName);
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
m_reply->close();
|
||||||
|
fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_output.setFileName(fileName);
|
||||||
|
fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName());
|
||||||
|
fileNameLabel->setToolTip(m_output.fileName());
|
||||||
|
if (m_requestFileName)
|
||||||
|
downloadReadyRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DownloadItem::saveFileName(const QString &directory) const
|
||||||
|
{
|
||||||
|
// Move this function into QNetworkReply to also get file name sent from the server
|
||||||
|
QString path = m_url.path();
|
||||||
|
if (!m_fileName.isEmpty())
|
||||||
|
path = m_fileName;
|
||||||
|
QFileInfo info(path);
|
||||||
|
QString baseName = info.completeBaseName();
|
||||||
|
QString endName = info.suffix();
|
||||||
|
|
||||||
|
if (baseName.isEmpty()) {
|
||||||
|
baseName = QLatin1String("unnamed_download");
|
||||||
|
qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
|
||||||
|
}
|
||||||
|
QString name = directory + baseName + QLatin1Char('.') + endName;
|
||||||
|
if (QFile::exists(name)) {
|
||||||
|
// already exists, don't overwrite
|
||||||
|
int i = 1;
|
||||||
|
do {
|
||||||
|
name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName;
|
||||||
|
} while (QFile::exists(name));
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DownloadItem::stop()
|
||||||
|
{
|
||||||
|
setUpdatesEnabled(false);
|
||||||
|
stopButton->setEnabled(false);
|
||||||
|
stopButton->hide();
|
||||||
|
tryAgainButton->setEnabled(true);
|
||||||
|
tryAgainButton->show();
|
||||||
|
setUpdatesEnabled(true);
|
||||||
|
m_reply->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::open()
|
||||||
|
{
|
||||||
|
QFileInfo info(m_output);
|
||||||
|
QString selectedFilter;
|
||||||
|
QStringList fileList;
|
||||||
|
fileList << info.absoluteFilePath();
|
||||||
|
SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter);
|
||||||
|
|
||||||
|
// load the files with the associated modules
|
||||||
|
if (!dict.isEmpty()) {
|
||||||
|
Gui::Document* doc = Gui::Application::Instance->activeDocument();
|
||||||
|
if (doc) {
|
||||||
|
for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
|
||||||
|
Gui::Application::Instance->importFrom(it.key().toUtf8(),
|
||||||
|
doc->getDocument()->getName(), it.value().toAscii());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
|
||||||
|
Gui::Application::Instance->open(it.key().toUtf8(), it.value().toAscii());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QUrl url = QUrl::fromLocalFile(info.absolutePath());
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::openFolder()
|
||||||
|
{
|
||||||
|
QFileInfo info(m_output);
|
||||||
|
QUrl url = QUrl::fromLocalFile(info.absolutePath());
|
||||||
|
QDesktopServices::openUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::tryAgain()
|
||||||
|
{
|
||||||
|
if (!tryAgainButton->isEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
tryAgainButton->setEnabled(false);
|
||||||
|
tryAgainButton->setVisible(false);
|
||||||
|
stopButton->setEnabled(true);
|
||||||
|
stopButton->setVisible(true);
|
||||||
|
progressBar->setVisible(true);
|
||||||
|
|
||||||
|
QNetworkReply *r = DownloadManager::getInstance()->networkAccessManager()->get(QNetworkRequest(m_url));
|
||||||
|
if (m_reply)
|
||||||
|
m_reply->deleteLater();
|
||||||
|
if (m_output.exists())
|
||||||
|
m_output.remove();
|
||||||
|
m_reply = r;
|
||||||
|
init();
|
||||||
|
/*emit*/ statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::contextMenuEvent (QContextMenuEvent * e)
|
||||||
|
{
|
||||||
|
QMenu menu;
|
||||||
|
QAction* a = menu.addAction(tr("Open containing folder"), this, SLOT(openFolder()));
|
||||||
|
a->setEnabled(m_output.exists());
|
||||||
|
menu.exec(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::downloadReadyRead()
|
||||||
|
{
|
||||||
|
if (m_requestFileName && m_output.fileName().isEmpty())
|
||||||
|
return;
|
||||||
|
if (!m_output.isOpen()) {
|
||||||
|
// in case someone else has already put a file there
|
||||||
|
if (!m_requestFileName)
|
||||||
|
getFileName();
|
||||||
|
if (!m_output.open(QIODevice::WriteOnly)) {
|
||||||
|
downloadInfoLabel->setText(tr("Error opening save file: %1")
|
||||||
|
.arg(m_output.errorString()));
|
||||||
|
stopButton->click();
|
||||||
|
/*emit*/ statusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadInfoLabel->setToolTip(m_url.toString());
|
||||||
|
/*emit*/ statusChanged();
|
||||||
|
}
|
||||||
|
if (-1 == m_output.write(m_reply->readAll())) {
|
||||||
|
downloadInfoLabel->setText(tr("Error saving: %1")
|
||||||
|
.arg(m_output.errorString()));
|
||||||
|
stopButton->click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::error(QNetworkReply::NetworkError)
|
||||||
|
{
|
||||||
|
qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url;
|
||||||
|
downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString()));
|
||||||
|
tryAgainButton->setEnabled(true);
|
||||||
|
tryAgainButton->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::metaDataChanged()
|
||||||
|
{
|
||||||
|
if (m_reply->hasRawHeader(QByteArray("Content-Disposition"))) {
|
||||||
|
QByteArray header = m_reply->rawHeader(QByteArray("Content-Disposition"));
|
||||||
|
int index = header.indexOf("filename=");
|
||||||
|
if (index >= 0) {
|
||||||
|
header = header.mid(index+9);
|
||||||
|
if (header.startsWith("\"") || header.startsWith("'"))
|
||||||
|
header = header.mid(1);
|
||||||
|
if (header.endsWith("\"") || header.endsWith("'"))
|
||||||
|
header.chop(1);
|
||||||
|
m_fileName = QUrl::fromPercentEncoding(header);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = header.indexOf("filename*=UTF-8''");
|
||||||
|
if (index >= 0) {
|
||||||
|
header = header.mid(index+17);
|
||||||
|
if (header.startsWith("\"") || header.startsWith("'"))
|
||||||
|
header = header.mid(1);
|
||||||
|
if (header.endsWith("\"") || header.endsWith("'"))
|
||||||
|
header.chop(1);
|
||||||
|
m_fileName = QUrl::fromPercentEncoding(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||||
|
if (!statusCode.isValid())
|
||||||
|
return;
|
||||||
|
int status = statusCode.toInt();
|
||||||
|
if (status != 200) {
|
||||||
|
QString reason = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||||
|
qDebug() << reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
||||||
|
{
|
||||||
|
m_bytesReceived = bytesReceived;
|
||||||
|
if (bytesTotal == -1) {
|
||||||
|
progressBar->setValue(0);
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
} else {
|
||||||
|
progressBar->setValue(bytesReceived);
|
||||||
|
progressBar->setMaximum(bytesTotal);
|
||||||
|
}
|
||||||
|
updateInfoLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::updateInfoLabel()
|
||||||
|
{
|
||||||
|
//if (m_reply->error() == QNetworkReply::NoError)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
qint64 bytesTotal = progressBar->maximum();
|
||||||
|
bool running = !downloadedSuccessfully();
|
||||||
|
|
||||||
|
// update info label
|
||||||
|
double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
|
||||||
|
double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed;
|
||||||
|
QString timeRemainingString = tr("seconds");
|
||||||
|
if (timeRemaining > 60) {
|
||||||
|
timeRemaining = timeRemaining / 60;
|
||||||
|
timeRemainingString = tr("minutes");
|
||||||
|
}
|
||||||
|
timeRemaining = floor(timeRemaining);
|
||||||
|
|
||||||
|
// When downloading the eta should never be 0
|
||||||
|
if (timeRemaining == 0)
|
||||||
|
timeRemaining = 1;
|
||||||
|
|
||||||
|
QString info;
|
||||||
|
if (running) {
|
||||||
|
QString remaining;
|
||||||
|
if (bytesTotal != 0)
|
||||||
|
remaining = tr("- %4 %5 remaining")
|
||||||
|
.arg(timeRemaining)
|
||||||
|
.arg(timeRemainingString);
|
||||||
|
info = QString(tr("%1 of %2 (%3/sec) %4"))
|
||||||
|
.arg(dataString(m_bytesReceived))
|
||||||
|
.arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
|
||||||
|
.arg(dataString((int)speed))
|
||||||
|
.arg(remaining);
|
||||||
|
} else {
|
||||||
|
if (m_bytesReceived == bytesTotal)
|
||||||
|
info = dataString(m_output.size());
|
||||||
|
else
|
||||||
|
info = tr("%1 of %2 - Stopped")
|
||||||
|
.arg(dataString(m_bytesReceived))
|
||||||
|
.arg(dataString(bytesTotal));
|
||||||
|
}
|
||||||
|
downloadInfoLabel->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DownloadItem::dataString(int size) const
|
||||||
|
{
|
||||||
|
QString unit;
|
||||||
|
if (size < 1024) {
|
||||||
|
unit = tr("bytes");
|
||||||
|
} else if (size < 1024*1024) {
|
||||||
|
size /= 1024;
|
||||||
|
unit = tr("kB");
|
||||||
|
} else {
|
||||||
|
size /= 1024*1024;
|
||||||
|
unit = tr("MB");
|
||||||
|
}
|
||||||
|
return QString(QLatin1String("%1 %2")).arg(size).arg(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadItem::downloading() const
|
||||||
|
{
|
||||||
|
return (progressBar->isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadItem::downloadedSuccessfully() const
|
||||||
|
{
|
||||||
|
return (stopButton->isHidden() && tryAgainButton->isHidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::finished()
|
||||||
|
{
|
||||||
|
progressBar->hide();
|
||||||
|
stopButton->setEnabled(false);
|
||||||
|
stopButton->hide();
|
||||||
|
m_output.close();
|
||||||
|
updateInfoLabel();
|
||||||
|
/*emit*/ statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_DownloadItem.cpp"
|
155
src/Gui/DownloadItem.h
Normal file
155
src/Gui/DownloadItem.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GUI_DIALOG_DOWNLOADITEM_H
|
||||||
|
#define GUI_DIALOG_DOWNLOADITEM_H
|
||||||
|
|
||||||
|
#include <QBasicTimer>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTime>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTableView>
|
||||||
|
|
||||||
|
class AutoSaver;
|
||||||
|
class QFileIconProvider;
|
||||||
|
|
||||||
|
class EditTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EditTableView(QWidget *parent = 0);
|
||||||
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void removeOne();
|
||||||
|
void removeAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SqueezeLabel : public QLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SqueezeLabel(QWidget *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class will call the save() slot on the parent object when the parent changes.
|
||||||
|
It will wait several seconds after changed() to combining multiple changes and
|
||||||
|
prevent continuous writing to disk.
|
||||||
|
*/
|
||||||
|
class AutoSaver : public QObject {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AutoSaver(QObject *parent);
|
||||||
|
~AutoSaver();
|
||||||
|
void saveIfNeccessary();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void changeOccurred();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void timerEvent(QTimerEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QBasicTimer m_timer;
|
||||||
|
QTime m_firstChange;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetworkAccessManager : public QNetworkAccessManager
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
NetworkAccessManager(QObject *parent = 0);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth);
|
||||||
|
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "ui_DownloadItem.h"
|
||||||
|
|
||||||
|
namespace Gui {
|
||||||
|
namespace Dialog {
|
||||||
|
class DownloadModel;
|
||||||
|
|
||||||
|
class DownloadItem : public QWidget, public Ui_DownloadItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void statusChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0);
|
||||||
|
bool downloading() const;
|
||||||
|
bool downloadedSuccessfully() const;
|
||||||
|
|
||||||
|
QUrl m_url;
|
||||||
|
QString m_fileName;
|
||||||
|
|
||||||
|
QFile m_output;
|
||||||
|
QNetworkReply *m_reply;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void stop();
|
||||||
|
void tryAgain();
|
||||||
|
void open();
|
||||||
|
void openFolder();
|
||||||
|
|
||||||
|
void downloadReadyRead();
|
||||||
|
void error(QNetworkReply::NetworkError code);
|
||||||
|
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
|
void metaDataChanged();
|
||||||
|
void finished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void contextMenuEvent(QContextMenuEvent *);
|
||||||
|
void getFileName();
|
||||||
|
void init();
|
||||||
|
void updateInfoLabel();
|
||||||
|
QString dataString(int size) const;
|
||||||
|
QString getDownloadDirectory() const;
|
||||||
|
QString saveFileName(const QString &directory) const;
|
||||||
|
|
||||||
|
bool m_requestFileName;
|
||||||
|
qint64 m_bytesReceived;
|
||||||
|
QTime m_downloadTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialog
|
||||||
|
} // namespace Gui
|
||||||
|
|
||||||
|
#endif // GUI_DIALOG_DOWNLOADITEM_H
|
140
src/Gui/DownloadItem.ui
Normal file
140
src/Gui/DownloadItem.ui
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DownloadItem</class>
|
||||||
|
<widget class="QWidget" name="DownloadItem">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>423</width>
|
||||||
|
<height>98</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="fileIcon">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Ico</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="SqueezeLabel" name="fileNameLabel" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text" stdset="0">
|
||||||
|
<string>Filename</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="SqueezeLabel" name="downloadInfoLabel" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text" stdset="0">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>17</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="tryAgainButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Icons/resource.qrc">
|
||||||
|
<normaloff>:/icons/view-refresh.svg</normaloff>:/icons/view-refresh.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="stopButton">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Icons/resource.qrc">
|
||||||
|
<normaloff>:/icons/process-stop.svg</normaloff>:/icons/process-stop.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="openButton">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Icons/resource.qrc">
|
||||||
|
<normaloff>:/icons/document-open.svg</normaloff>:/icons/document-open.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>17</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>SqueezeLabel</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>DownloadItem.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="Icons/resource.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
303
src/Gui/DownloadManager.cpp
Normal file
303
src/Gui/DownloadManager.cpp
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "PreCompiled.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QFileIconProvider>
|
||||||
|
#include <QWebSettings>
|
||||||
|
|
||||||
|
#include "DownloadItem.h"
|
||||||
|
#include "DownloadManager.h"
|
||||||
|
#include "ui_DownloadManager.h"
|
||||||
|
#include "DockWindowManager.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
using namespace Gui::Dialog;
|
||||||
|
|
||||||
|
/* TRANSLATOR Gui::Dialog::DownloadManager */
|
||||||
|
|
||||||
|
DownloadManager* DownloadManager::self = 0;
|
||||||
|
|
||||||
|
DownloadManager* DownloadManager::getInstance()
|
||||||
|
{
|
||||||
|
if (!self)
|
||||||
|
self = new DownloadManager(Gui::getMainWindow());
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadManager::DownloadManager(QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, m_autoSaver(new AutoSaver(this))
|
||||||
|
, m_manager(new NetworkAccessManager(this))
|
||||||
|
, m_iconProvider(0)
|
||||||
|
, m_removePolicy(Never)
|
||||||
|
, ui(new Ui_DownloadManager())
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->downloadsView->setShowGrid(false);
|
||||||
|
ui->downloadsView->verticalHeader()->hide();
|
||||||
|
ui->downloadsView->horizontalHeader()->hide();
|
||||||
|
ui->downloadsView->setAlternatingRowColors(true);
|
||||||
|
ui->downloadsView->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
m_model = new DownloadModel(this);
|
||||||
|
ui->downloadsView->setModel(m_model);
|
||||||
|
connect(ui->cleanupButton, SIGNAL(clicked()), this, SLOT(cleanup()));
|
||||||
|
load();
|
||||||
|
|
||||||
|
Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
|
||||||
|
QDockWidget* dw = pDockMgr->addDockWindow(QT_TR_NOOP("Download Manager"),
|
||||||
|
this, Qt::BottomDockWidgetArea);
|
||||||
|
dw->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable);
|
||||||
|
dw->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadManager::~DownloadManager()
|
||||||
|
{
|
||||||
|
m_autoSaver->changeOccurred();
|
||||||
|
m_autoSaver->saveIfNeccessary();
|
||||||
|
if (m_iconProvider)
|
||||||
|
delete m_iconProvider;
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DownloadManager::activeDownloads() const
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < m_downloads.count(); ++i) {
|
||||||
|
if (m_downloads.at(i)->stopButton->isEnabled())
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::download(const QNetworkRequest &request, bool requestFileName)
|
||||||
|
{
|
||||||
|
if (request.url().isEmpty())
|
||||||
|
return;
|
||||||
|
handleUnsupportedContent(m_manager->get(request), requestFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName)
|
||||||
|
{
|
||||||
|
if (!reply || reply->url().isEmpty())
|
||||||
|
return;
|
||||||
|
QVariant header = reply->header(QNetworkRequest::ContentLengthHeader);
|
||||||
|
bool ok;
|
||||||
|
int size = header.toInt(&ok);
|
||||||
|
if (ok && size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DownloadItem *item = new DownloadItem(reply, requestFileName, this);
|
||||||
|
addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::addItem(DownloadItem *item)
|
||||||
|
{
|
||||||
|
connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow()));
|
||||||
|
int row = m_downloads.count();
|
||||||
|
m_model->beginInsertRows(QModelIndex(), row, row);
|
||||||
|
m_downloads.append(item);
|
||||||
|
m_model->endInsertRows();
|
||||||
|
updateItemCount();
|
||||||
|
show();
|
||||||
|
ui->downloadsView->setIndexWidget(m_model->index(row, 0), item);
|
||||||
|
QIcon icon = style()->standardIcon(QStyle::SP_FileIcon);
|
||||||
|
item->fileIcon->setPixmap(icon.pixmap(48, 48));
|
||||||
|
ui->downloadsView->setRowHeight(row, item->sizeHint().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::updateRow()
|
||||||
|
{
|
||||||
|
DownloadItem *item = qobject_cast<DownloadItem*>(sender());
|
||||||
|
int row = m_downloads.indexOf(item);
|
||||||
|
if (-1 == row)
|
||||||
|
return;
|
||||||
|
if (!m_iconProvider)
|
||||||
|
m_iconProvider = new QFileIconProvider();
|
||||||
|
QIcon icon = m_iconProvider->icon(item->m_output.fileName());
|
||||||
|
if (icon.isNull())
|
||||||
|
icon = style()->standardIcon(QStyle::SP_FileIcon);
|
||||||
|
item->fileIcon->setPixmap(icon.pixmap(48, 48));
|
||||||
|
ui->downloadsView->setRowHeight(row, item->minimumSizeHint().height());
|
||||||
|
|
||||||
|
bool remove = false;
|
||||||
|
QWebSettings *globalSettings = QWebSettings::globalSettings();
|
||||||
|
if (!item->downloading()
|
||||||
|
&& globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
|
||||||
|
remove = true;
|
||||||
|
|
||||||
|
if (item->downloadedSuccessfully()
|
||||||
|
&& removePolicy() == DownloadManager::SuccessFullDownload) {
|
||||||
|
remove = true;
|
||||||
|
}
|
||||||
|
if (remove)
|
||||||
|
m_model->removeRow(row);
|
||||||
|
|
||||||
|
ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadManager::RemovePolicy DownloadManager::removePolicy() const
|
||||||
|
{
|
||||||
|
return m_removePolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::setRemovePolicy(RemovePolicy policy)
|
||||||
|
{
|
||||||
|
if (policy == m_removePolicy)
|
||||||
|
return;
|
||||||
|
m_removePolicy = policy;
|
||||||
|
m_autoSaver->changeOccurred();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::save() const
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup(QLatin1String("downloadmanager"));
|
||||||
|
QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
|
||||||
|
settings.setValue(QLatin1String("removeDownloadsPolicy"), QLatin1String(removePolicyEnum.valueToKey(m_removePolicy)));
|
||||||
|
settings.setValue(QLatin1String("size"), size());
|
||||||
|
if (m_removePolicy == Exit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_downloads.count(); ++i) {
|
||||||
|
QString key = QString(QLatin1String("download_%1_")).arg(i);
|
||||||
|
settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url);
|
||||||
|
settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath());
|
||||||
|
settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully());
|
||||||
|
}
|
||||||
|
int i = m_downloads.count();
|
||||||
|
QString key = QString(QLatin1String("download_%1_")).arg(i);
|
||||||
|
while (settings.contains(key + QLatin1String("url"))) {
|
||||||
|
settings.remove(key + QLatin1String("url"));
|
||||||
|
settings.remove(key + QLatin1String("location"));
|
||||||
|
settings.remove(key + QLatin1String("done"));
|
||||||
|
key = QString(QLatin1String("download_%1_")).arg(++i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::load()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup(QLatin1String("downloadmanager"));
|
||||||
|
QSize size = settings.value(QLatin1String("size")).toSize();
|
||||||
|
if (size.isValid())
|
||||||
|
resize(size);
|
||||||
|
QByteArray value = settings.value(QLatin1String("removeDownloadsPolicy"), QLatin1String("Never")).toByteArray();
|
||||||
|
QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
|
||||||
|
m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ?
|
||||||
|
Never :
|
||||||
|
static_cast<RemovePolicy>(removePolicyEnum.keyToValue(value));
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
QString key = QString(QLatin1String("download_%1_")).arg(i);
|
||||||
|
while (settings.contains(key + QLatin1String("url"))) {
|
||||||
|
QUrl url = settings.value(key + QLatin1String("url")).toUrl();
|
||||||
|
QString fileName = settings.value(key + QLatin1String("location")).toString();
|
||||||
|
bool done = settings.value(key + QLatin1String("done"), true).toBool();
|
||||||
|
if (!url.isEmpty() && !fileName.isEmpty()) {
|
||||||
|
DownloadItem *item = new DownloadItem(0, this);
|
||||||
|
item->m_output.setFileName(fileName);
|
||||||
|
item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName());
|
||||||
|
item->m_url = url;
|
||||||
|
item->stopButton->setVisible(false);
|
||||||
|
item->stopButton->setEnabled(false);
|
||||||
|
item->tryAgainButton->setVisible(!done);
|
||||||
|
item->tryAgainButton->setEnabled(!done);
|
||||||
|
item->progressBar->setVisible(!done);
|
||||||
|
addItem(item);
|
||||||
|
}
|
||||||
|
key = QString(QLatin1String("download_%1_")).arg(++i);
|
||||||
|
}
|
||||||
|
ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::cleanup()
|
||||||
|
{
|
||||||
|
if (m_downloads.isEmpty())
|
||||||
|
return;
|
||||||
|
m_model->removeRows(0, m_downloads.count());
|
||||||
|
updateItemCount();
|
||||||
|
if (m_downloads.isEmpty() && m_iconProvider) {
|
||||||
|
delete m_iconProvider;
|
||||||
|
m_iconProvider = 0;
|
||||||
|
}
|
||||||
|
m_autoSaver->changeOccurred();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadManager::updateItemCount()
|
||||||
|
{
|
||||||
|
int count = m_downloads.count();
|
||||||
|
ui->itemCount->setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
, m_downloadManager(downloadManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DownloadModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (index.row() < 0 || index.row() >= rowCount(index.parent()))
|
||||||
|
return QVariant();
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
if (!m_downloadManager->m_downloads.at(index.row())->downloadedSuccessfully())
|
||||||
|
return m_downloadManager->m_downloads.at(index.row())->downloadInfoLabel->text();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
int DownloadModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return (parent.isValid()) ? 0 : m_downloadManager->m_downloads.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int lastRow = row + count - 1;
|
||||||
|
for (int i = lastRow; i >= row; --i) {
|
||||||
|
if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully()
|
||||||
|
|| m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) {
|
||||||
|
beginRemoveRows(parent, i, i);
|
||||||
|
m_downloadManager->m_downloads.takeAt(i)->deleteLater();
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_downloadManager->m_autoSaver->changeOccurred();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_DownloadManager.cpp"
|
116
src/Gui/DownloadManager.h
Normal file
116
src/Gui/DownloadManager.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GUI_DIALOG_DOWNLOADMANAGER_H
|
||||||
|
#define GUI_DIALOG_DOWNLOADMANAGER_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
class AutoSaver;
|
||||||
|
class QFileIconProvider;
|
||||||
|
|
||||||
|
namespace Gui {
|
||||||
|
namespace Dialog {
|
||||||
|
class DownloadItem;
|
||||||
|
class DownloadModel;
|
||||||
|
class Ui_DownloadManager;
|
||||||
|
|
||||||
|
class GuiExport DownloadManager : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy)
|
||||||
|
Q_ENUMS(RemovePolicy)
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum RemovePolicy {
|
||||||
|
Never,
|
||||||
|
Exit,
|
||||||
|
SuccessFullDownload
|
||||||
|
};
|
||||||
|
|
||||||
|
static DownloadManager* getInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DownloadManager(QWidget *parent = 0);
|
||||||
|
~DownloadManager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int activeDownloads() const;
|
||||||
|
QNetworkAccessManager * networkAccessManager()
|
||||||
|
{ return m_manager; }
|
||||||
|
|
||||||
|
RemovePolicy removePolicy() const;
|
||||||
|
void setRemovePolicy(RemovePolicy policy);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void download(const QNetworkRequest &request, bool requestFileName = false);
|
||||||
|
inline void download(const QUrl &url, bool requestFileName = false)
|
||||||
|
{ download(QNetworkRequest(url), requestFileName); }
|
||||||
|
void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false);
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void save() const;
|
||||||
|
void updateRow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addItem(DownloadItem *item);
|
||||||
|
void updateItemCount();
|
||||||
|
void load();
|
||||||
|
|
||||||
|
AutoSaver *m_autoSaver;
|
||||||
|
DownloadModel *m_model;
|
||||||
|
QNetworkAccessManager *m_manager;
|
||||||
|
QFileIconProvider *m_iconProvider;
|
||||||
|
QList<DownloadItem*> m_downloads;
|
||||||
|
RemovePolicy m_removePolicy;
|
||||||
|
friend class DownloadModel;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui_DownloadManager* ui;
|
||||||
|
static DownloadManager* self;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DownloadModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
friend class DownloadManager;
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DownloadModel(DownloadManager *downloadManager, QObject *parent = 0);
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
|
||||||
|
|
||||||
|
private:
|
||||||
|
DownloadManager *m_downloadManager;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialog
|
||||||
|
} // namespace Gui
|
||||||
|
|
||||||
|
#endif // GUI_DIALOG_DOWNLOADMANAGER_H
|
83
src/Gui/DownloadManager.ui
Normal file
83
src/Gui/DownloadManager.ui
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<ui version="4.0" >
|
||||||
|
<class>Gui::Dialog::DownloadManager</class>
|
||||||
|
<widget class="QDialog" name="Gui::Dialog::DownloadManager" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>332</width>
|
||||||
|
<height>252</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Downloads</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout" >
|
||||||
|
<property name="margin" >
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing" >
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0" colspan="3" >
|
||||||
|
<widget class="EditTableView" name="downloadsView" />
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" >
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cleanupButton" >
|
||||||
|
<property name="enabled" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Clean up</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0" >
|
||||||
|
<size>
|
||||||
|
<width>58</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" >
|
||||||
|
<widget class="QLabel" name="itemCount" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>0 Items</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2" >
|
||||||
|
<spacer name="horizontalSpacer" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0" >
|
||||||
|
<size>
|
||||||
|
<width>148</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>EditTableView</class>
|
||||||
|
<extends>QTableView</extends>
|
||||||
|
<header>DownloadItem.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -26,11 +26,14 @@
|
||||||
# include <QApplication>
|
# include <QApplication>
|
||||||
# include <QButtonGroup>
|
# include <QButtonGroup>
|
||||||
# include <QComboBox>
|
# include <QComboBox>
|
||||||
|
# include <QDesktopServices>
|
||||||
# include <QGridLayout>
|
# include <QGridLayout>
|
||||||
# include <QGroupBox>
|
# include <QGroupBox>
|
||||||
# include <QLineEdit>
|
# include <QLineEdit>
|
||||||
# include <QPushButton>
|
# include <QPushButton>
|
||||||
# include <QRadioButton>
|
# include <QRadioButton>
|
||||||
|
# include <QStyle>
|
||||||
|
# include <QUrl>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Base/Parameter.h>
|
#include <Base/Parameter.h>
|
||||||
|
@ -45,6 +48,32 @@ using namespace Gui;
|
||||||
|
|
||||||
/* TRANSLATOR Gui::FileDialog */
|
/* TRANSLATOR Gui::FileDialog */
|
||||||
|
|
||||||
|
FileDialog::FileDialog(QWidget * parent)
|
||||||
|
: QFileDialog(parent)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(filterSelected(const QString&)),
|
||||||
|
this, SLOT(onSelectedFilter(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog::~FileDialog()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDialog::onSelectedFilter(const QString& filter)
|
||||||
|
{
|
||||||
|
QRegExp rx(QLatin1String("\\(\\*.(\\w+)"));
|
||||||
|
QString suf = selectedFilter();
|
||||||
|
if (rx.indexIn(suf) >= 0) {
|
||||||
|
suf = rx.cap(1);
|
||||||
|
setDefaultSuffix(suf.toLower());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDialog::accept()
|
||||||
|
{
|
||||||
|
QFileDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a convenience static function that will return a file name selected by the user. The file does not have to exist.
|
* This is a convenience static function that will return a file name selected by the user. The file does not have to exist.
|
||||||
*/
|
*/
|
||||||
|
@ -84,7 +113,37 @@ QString FileDialog::getSaveFileName (QWidget * parent, const QString & caption,
|
||||||
// NOTE: We must not change the specified file name afterwards as we may return the name of an already
|
// NOTE: We must not change the specified file name afterwards as we may return the name of an already
|
||||||
// existing file. Hence we must extract the first matching suffix from the filter list and append it
|
// existing file. Hence we must extract the first matching suffix from the filter list and append it
|
||||||
// before showing the file dialog.
|
// before showing the file dialog.
|
||||||
|
#if defined(FC_OS_LINUX)
|
||||||
|
QList<QUrl> urls;
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(getWorkingDirectory());
|
||||||
|
|
||||||
|
QString file;
|
||||||
|
FileDialog dlg(parent);
|
||||||
|
dlg.setWindowTitle(windowTitle);
|
||||||
|
dlg.setSidebarUrls(urls);
|
||||||
|
dlg.setIconProvider(new FileIconProvider());
|
||||||
|
dlg.setFileMode(QFileDialog::AnyFile);
|
||||||
|
dlg.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
dlg.setDirectory(dirName);
|
||||||
|
dlg.setOptions(options);
|
||||||
|
dlg.setFilters(filter.split(QLatin1String(";;")));
|
||||||
|
dlg.onSelectedFilter(dlg.selectedFilter());
|
||||||
|
dlg.setNameFilterDetailsVisible(true);
|
||||||
|
dlg.setConfirmOverwrite(true);
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
if (selectedFilter)
|
||||||
|
*selectedFilter = dlg.selectedFilter();
|
||||||
|
file = dlg.selectedFiles().front();
|
||||||
|
}
|
||||||
|
#else
|
||||||
QString file = QFileDialog::getSaveFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
|
QString file = QFileDialog::getSaveFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
|
||||||
|
#endif
|
||||||
if (!file.isEmpty()) {
|
if (!file.isEmpty()) {
|
||||||
setWorkingDirectory(file);
|
setWorkingDirectory(file);
|
||||||
return file;
|
return file;
|
||||||
|
@ -129,7 +188,36 @@ QString FileDialog::getOpenFileName(QWidget * parent, const QString & caption, c
|
||||||
#if defined(FC_OS_MACOSX)
|
#if defined(FC_OS_MACOSX)
|
||||||
options |= QFileDialog::DontUseNativeDialog;
|
options |= QFileDialog::DontUseNativeDialog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(FC_OS_LINUX)
|
||||||
|
QList<QUrl> urls;
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(getWorkingDirectory());
|
||||||
|
|
||||||
|
QString file;
|
||||||
|
FileDialog dlg(parent);
|
||||||
|
dlg.setWindowTitle(windowTitle);
|
||||||
|
dlg.setSidebarUrls(urls);
|
||||||
|
dlg.setIconProvider(new FileIconProvider());
|
||||||
|
dlg.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
dlg.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
dlg.setDirectory(dirName);
|
||||||
|
dlg.setOptions(options);
|
||||||
|
dlg.setFilters(filter.split(QLatin1String(";;")));
|
||||||
|
dlg.setNameFilterDetailsVisible(true);
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
if (selectedFilter)
|
||||||
|
*selectedFilter = dlg.selectedFilter();
|
||||||
|
file = dlg.selectedFiles().front();
|
||||||
|
}
|
||||||
|
#else
|
||||||
QString file = QFileDialog::getOpenFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
|
QString file = QFileDialog::getOpenFileName(parent, windowTitle, dirName, filter, selectedFilter, options);
|
||||||
|
#endif
|
||||||
if (!file.isEmpty()) {
|
if (!file.isEmpty()) {
|
||||||
setWorkingDirectory(file);
|
setWorkingDirectory(file);
|
||||||
return file;
|
return file;
|
||||||
|
@ -155,7 +243,36 @@ QStringList FileDialog::getOpenFileNames (QWidget * parent, const QString & capt
|
||||||
#if defined(FC_OS_MACOSX)
|
#if defined(FC_OS_MACOSX)
|
||||||
options |= QFileDialog::DontUseNativeDialog;
|
options |= QFileDialog::DontUseNativeDialog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(FC_OS_LINUX)
|
||||||
|
QList<QUrl> urls;
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation));
|
||||||
|
urls << QUrl::fromLocalFile(getWorkingDirectory());
|
||||||
|
|
||||||
|
QStringList files;
|
||||||
|
FileDialog dlg(parent);
|
||||||
|
dlg.setWindowTitle(windowTitle);
|
||||||
|
dlg.setSidebarUrls(urls);
|
||||||
|
dlg.setIconProvider(new FileIconProvider());
|
||||||
|
dlg.setFileMode(QFileDialog::ExistingFiles);
|
||||||
|
dlg.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
dlg.setDirectory(dirName);
|
||||||
|
dlg.setOptions(options);
|
||||||
|
dlg.setFilters(filter.split(QLatin1String(";;")));
|
||||||
|
dlg.setNameFilterDetailsVisible(true);
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
if (selectedFilter)
|
||||||
|
*selectedFilter = dlg.selectedFilter();
|
||||||
|
files = dlg.selectedFiles();
|
||||||
|
}
|
||||||
|
#else
|
||||||
QStringList files = QFileDialog::getOpenFileNames(parent, windowTitle, dirName, filter, selectedFilter, options);
|
QStringList files = QFileDialog::getOpenFileNames(parent, windowTitle, dirName, filter, selectedFilter, options);
|
||||||
|
#endif
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
setWorkingDirectory(files.front());
|
setWorkingDirectory(files.front());
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,14 @@ public:
|
||||||
|
|
||||||
static QString getWorkingDirectory();
|
static QString getWorkingDirectory();
|
||||||
static void setWorkingDirectory( const QString& );
|
static void setWorkingDirectory( const QString& );
|
||||||
|
|
||||||
|
FileDialog(QWidget * parent = 0);
|
||||||
|
~FileDialog();
|
||||||
|
|
||||||
|
void accept();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onSelectedFilter(const QString&);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
#ifndef _PreComp_
|
#ifndef _PreComp_
|
||||||
# include <QMenu>
|
# include <QMenu>
|
||||||
# include <QMouseEvent>
|
# include <QMouseEvent>
|
||||||
|
# include <Inventor/nodes/SoCamera.h>
|
||||||
#endif
|
#endif
|
||||||
#include <Inventor/SbVec2s.h>
|
#include <Inventor/SbVec2s.h>
|
||||||
#include "View3DInventorViewer.h"
|
#include "View3DInventorViewer.h"
|
||||||
#include "GLPainter.h"
|
|
||||||
|
|
||||||
#include "Flag.h"
|
#include "Flag.h"
|
||||||
|
|
||||||
|
@ -455,4 +455,76 @@ QSize FlagLayout::calculateSize(SizeType sizeType) const
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TYPESYSTEM_SOURCE_ABSTRACT(Gui::GLFlagWindow, Gui::GLGraphicsItem);
|
||||||
|
|
||||||
|
GLFlagWindow::GLFlagWindow(View3DInventorViewer* view) : _viewer(view), _flagLayout(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFlagWindow::~GLFlagWindow()
|
||||||
|
{
|
||||||
|
deleteFlags();
|
||||||
|
if (_flagLayout)
|
||||||
|
_flagLayout->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLFlagWindow::deleteFlags()
|
||||||
|
{
|
||||||
|
if (_flagLayout) {
|
||||||
|
int ct = _flagLayout->count();
|
||||||
|
for (int i=0; i<ct;i++) {
|
||||||
|
QWidget* flag = _flagLayout->itemAt(0)->widget();
|
||||||
|
if (flag) {
|
||||||
|
_flagLayout->removeWidget(flag);
|
||||||
|
flag->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLFlagWindow::addFlag(Flag* item, FlagLayout::Position pos)
|
||||||
|
{
|
||||||
|
if (!_flagLayout) {
|
||||||
|
_flagLayout = new FlagLayout(3);
|
||||||
|
_viewer->getGLWidget()->setLayout(_flagLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setParent(_viewer->getGLWidget());
|
||||||
|
_flagLayout->addWidget(item, pos);
|
||||||
|
item->show();
|
||||||
|
_viewer->scheduleRedraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLFlagWindow::removeFlag(Flag* item)
|
||||||
|
{
|
||||||
|
if (_flagLayout) {
|
||||||
|
_flagLayout->removeWidget(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLFlagWindow::paintGL()
|
||||||
|
{
|
||||||
|
// draw lines for the flags
|
||||||
|
if (_flagLayout) {
|
||||||
|
// it can happen that the GL widget gets replaced internally by SoQt which
|
||||||
|
// causes to destroy the FlagLayout instance
|
||||||
|
int ct = _flagLayout->count();
|
||||||
|
const SbViewportRegion vp = _viewer->getViewportRegion();
|
||||||
|
SbVec2s size = vp.getViewportSizePixels();
|
||||||
|
float aspectratio = float(size[0])/float(size[1]);
|
||||||
|
SbViewVolume vv = _viewer->getCamera()->getViewVolume(aspectratio);
|
||||||
|
for (int i=0; i<ct;i++) {
|
||||||
|
Flag* flag = qobject_cast<Flag*>(_flagLayout->itemAt(i)->widget());
|
||||||
|
if (flag) {
|
||||||
|
SbVec3f pt = flag->getOrigin();
|
||||||
|
vv.projectToScreen(pt, pt);
|
||||||
|
int tox = (int)(pt[0] * size[0]);
|
||||||
|
int toy = (int)((1.0f-pt[1]) * size[1]);
|
||||||
|
flag->drawLine(_viewer, tox, toy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_Flag.cpp"
|
#include "moc_Flag.cpp"
|
||||||
|
|
|
@ -29,9 +29,11 @@
|
||||||
#include <QWidgetItem>
|
#include <QWidgetItem>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <Inventor/SbVec3f.h>
|
#include <Inventor/SbVec3f.h>
|
||||||
|
#include <Gui/GLPainter.h>
|
||||||
|
|
||||||
namespace Gui {
|
namespace Gui {
|
||||||
class View3DInventorViewer;
|
class View3DInventorViewer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Werner Mayer
|
* @author Werner Mayer
|
||||||
*/
|
*/
|
||||||
|
@ -98,6 +100,8 @@ private:
|
||||||
|
|
||||||
class FlagLayout : public QLayout
|
class FlagLayout : public QLayout
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Position { TopLeft, TopRight, BottomLeft, BottomRight };
|
enum Position { TopLeft, TopRight, BottomLeft, BottomRight };
|
||||||
|
|
||||||
|
@ -136,6 +140,24 @@ private:
|
||||||
QList<ItemWrapper *> list;
|
QList<ItemWrapper *> list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GuiExport GLFlagWindow : public Gui::GLGraphicsItem
|
||||||
|
{
|
||||||
|
TYPESYSTEM_HEADER();
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLFlagWindow(View3DInventorViewer*);
|
||||||
|
virtual ~GLFlagWindow();
|
||||||
|
void addFlag(Flag* item, FlagLayout::Position pos);
|
||||||
|
void removeFlag(Flag* item);
|
||||||
|
void deleteFlags();
|
||||||
|
|
||||||
|
void paintGL();
|
||||||
|
|
||||||
|
private:
|
||||||
|
View3DInventorViewer* _viewer;
|
||||||
|
FlagLayout* _flagLayout;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Gui
|
} // namespace Gui
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
using namespace Gui;
|
using namespace Gui;
|
||||||
|
|
||||||
|
TYPESYSTEM_SOURCE_ABSTRACT(Gui::GLGraphicsItem, Base::BaseClass);
|
||||||
|
|
||||||
GLPainter::GLPainter() : viewer(0), logicOp(false), lineStipple(false)
|
GLPainter::GLPainter() : viewer(0), logicOp(false), lineStipple(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <Base/BaseClass.h>
|
||||||
|
|
||||||
namespace Gui {
|
namespace Gui {
|
||||||
class View3DInventorViewer;
|
class View3DInventorViewer;
|
||||||
class GuiExport GLPainter
|
class GuiExport GLPainter
|
||||||
|
@ -71,6 +73,20 @@ private:
|
||||||
bool lineStipple;
|
bool lineStipple;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GuiExport GLGraphicsItem : public Base::BaseClass
|
||||||
|
{
|
||||||
|
TYPESYSTEM_HEADER();
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLGraphicsItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~GLGraphicsItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual void paintGL() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Gui
|
} // namespace Gui
|
||||||
|
|
||||||
#endif // GUI_GLPAINTER_H
|
#endif // GUI_GLPAINTER_H
|
||||||
|
|
BIN
src/Gui/Icons/freecad-icon-16.png
Normal file
BIN
src/Gui/Icons/freecad-icon-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 862 B |
BIN
src/Gui/Icons/freecad-icon-32.png
Normal file
BIN
src/Gui/Icons/freecad-icon-32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
src/Gui/Icons/freecad-icon-48.png
Normal file
BIN
src/Gui/Icons/freecad-icon-48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
src/Gui/Icons/freecad-icon-64.png
Normal file
BIN
src/Gui/Icons/freecad-icon-64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 153 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user