Merge branch 'refs/heads/master' into jriegel/develop-fem

This commit is contained in:
jriegel 2013-07-08 19:46:54 +02:00
commit 9d05dcc85c
325 changed files with 19291 additions and 6585 deletions

View File

@ -212,26 +212,60 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
if(NOT DEFINED OCE_DIR)
if(UNIX)
set(OCE_DIR "/usr/local/share/cmake/")
else()
elseif(WIN32)
set(OCE_DIR "c:/OCE-0.4.0/share/cmake")
endif()
endif()
find_package ( OCE )
find_package (OCE QUIET)
if(${OCE_FOUND})
message("-- OpenCASCADE Community Edition has been found.")
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
set( OCC_OCAF_LIBRARIES "TKCAF;TKXCAF;TKLCAF;TKXDESTEP;TKXDEIGES;TKMeshVS;TKAdvTools" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake
#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_FOUND ${OCE_FOUND})
else() #look for OpenCASCADE
find_package(OpenCasCade)
IF(NOT OCC_FOUND)
MESSAGE("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
ELSE()
MESSAGE("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}")
MESSAGE("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}")
ENDIF()
if(NOT OCC_FOUND)
message("Neither OpenCASCADE Community Edition nor OpenCasCade were found: will not build CAD modules!")
else()
message("-- OpenCASCADE include directory: ${OCC_INCLUDE_PATH}")
message("-- OpenCASCADE shared libraries directory: ${OCC_LIB_PATH}")
endif()
endif()
# -------------------------------- Salome SMESH --------------------------
@ -362,6 +396,17 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X)
find_package(Spnav)
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 ------------------------------
find_package(Matplotlib)
@ -441,8 +486,14 @@ IF(APPLE)
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
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(data)
#endif()
# ================================================================================
# == Packaging ===================================================================

View File

@ -83,3 +83,7 @@ because it contains some Fortran code.
project.
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.
* FreeType
http://stackoverflow.com/questions/6207176/compiling-freetype-to-dll-as-opposed-to-static-library

View File

@ -13,6 +13,7 @@ IF (WIN32)
FIND_PATH(COIN3D_INCLUDE_DIR Inventor/So.h
/usr/include
/usr/local/include
/usr/include/coin
)
FIND_LIBRARY(COIN3D_LIBRARY Coin

View File

@ -196,6 +196,8 @@ include(AddFileDependencies)
macro(fc_wrap_cpp outfiles )
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)
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)

View File

@ -207,6 +207,8 @@ include(AddFileDependencies)
macro(fc_wrap_cpp outfiles )
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)
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)

View File

@ -219,6 +219,8 @@ include(AddFileDependencies)
macro(fc_wrap_cpp outfiles )
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)
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)
@ -392,5 +394,19 @@ SET(EIGEN3_INCLUDE_DIR ${FREECAD_LIBPACK_DIR}/include/eigen3)
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)

View File

@ -230,6 +230,8 @@ include(AddFileDependencies)
macro(fc_wrap_cpp outfiles )
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)
foreach(it ${moc_files})
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_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)

View File

@ -12,7 +12,10 @@ ADD_CUSTOM_TARGET(Example_data ALL
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(
FILES

View File

@ -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
* 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
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
* 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
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
* 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
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
* Add 'dfsg' extension to upstream version, upstream sources are unchanged.

View File

@ -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>
Vcs-Browser: http://git.debian.org/?p=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
Build-Depends: debhelper (>= 7.0.50~), autotools-dev, libtool, automake,
autoconf, libboost-dev, libboost-date-time-dev, libboost-filesystem-dev,
Homepage: https://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page
Build-Depends: debhelper (>= 7.0.50~), cmake,
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,
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,
libcoin60-dev, libsoqt4-dev (>= 1.4.2~svn20090224), libeigen3-dev, libgl1-mesa-dev,
zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev, libopencascade-modeling-dev,
libcoin60-dev, libsoqt4-dev, libeigen3-dev,
zlib1g-dev, libxerces-c2-dev, libopencascade-foundation-dev,
libopencascade-modeling-dev, libopencascade-ocaf-dev,
libopencascade-visualization-dev, python-cxx-dev, libswscale-dev,
libzipios++-dev, swig, gfortran, libqtwebkit-dev
Standards-Version: 3.9.2
libzipios++-dev, swig, gfortran, f2c, libqtwebkit-dev, libspnav-dev, libfreetype6-dev
Standards-Version: 3.9.1
Package: freecad
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
Recommends: python-pivy python-matplotlib
Recommends: python-pivy, python
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.
It features some key concepts like macro recording, workbenches, ability
to run as a server and dynamically loadable application extensions and

File diff suppressed because it is too large Load Diff

8
package/debian/dirs Normal file
View 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

View File

@ -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

View File

@ -0,0 +1 @@
debian/tmp/usr/doc/*

View File

@ -10,7 +10,7 @@ Exec=/usr/bin/freecad %F
Path=/usr/lib/freecad
Terminal=false
Type=Application
Icon=/usr/share/freecad/freecad.xpm
Icon=freecad
Categories=Graphics;Science;Engineering
StartupNotify=true
GenericName[de_DE]=Feature-basierter parametrischer Modellierer

View File

@ -0,0 +1 @@
debian/freecad.1

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="application/x-extension-fcstd">
<sub-class-of type="application/zip"/>
<!-- <sub-class-of type="application/zip"/> -->
<comment>FreeCAD document files</comment>
<glob pattern="*.fcstd"/>
</mime-type>

View File

@ -1,4 +0,0 @@
[Thumbnailer Entry]
TryExec=freecad-thumbnailer
Exec=freecad-thumbnailer -s %s %u %o
MimeType=application/x-extension-fcstd;

View File

@ -2,5 +2,5 @@
section="Applications/Science/Engineering"\
title="FreeCAD"\
command="/usr/bin/freecad"\
icon="/usr/share/freecad/freecad.xpm"
icon="/usr/share/pixmaps/freecad.xpm"

View File

@ -1,11 +1,16 @@
#!/usr/bin/python
import sys, zipfile, md5
import sys, zipfile
import getopt
import gnomevfs
from urlparse import urlparse
from urlparse import unquote
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]
try:
@ -19,8 +24,9 @@ try:
if image in files:
image=zfile.read(image)
else:
freecad=open("/usr/share/freecad/freecad-doc.png")
image=freecad.read()
#freecad=open("/usr/share/freecad/freecad-doc.png")
#image=freecad.read()
sys.exit(1)
thumb=open(outfile,"wb")
thumb.write(image)

View 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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -4,7 +4,7 @@
# Uncomment this to turn on verbose mode.
#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
# from having to guess our platform (since we know it already)
@ -19,58 +19,32 @@ else
CFLAGS += -O2
endif
patch-stamp:
touch $@
configure: autogen.sh patch-stamp
configure:
dh_testdir
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 \
cp -a $$autotools_mod_file $$autotools_mod_file.setaside; \
done
chmod u+x autogen.sh
./autogen.sh
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
cmake . \
-DFREECAD_BUILD_DEBIAN=ON \
-DCMAKE_INSTALL_PREFIX=/usr/lib/freecad \
-DCMAKE_INSTALL_MANDIR=/usr/share/man \
-DCMAKE_INSTALL_INFODIR=/usr/share/info \
-DCMAKE_INSTALL_DATADIR=/usr/share/freecad \
-DCMAKE_INSTALL_INCLUDEDIR=/usr/include/freecad \
-DCMAKE_INSTALL_DOCDIR=/usr/share/doc/freecad
build: build-stamp
build-stamp: config.status
build-stamp: configure
dh_testdir
$(MAKE)
touch $@
clean:
mv src/Build/Version.h src/Build/Version.h.old
dh clean
mv src/Build/Version.h.old src/Build/Version.h
rm -f build-stamp
find -name '*.pyc' | xargs rm -f
find -name 'moc_*.cpp' | xargs rm -f
find -name '*.lo' | xargs rm -f
find -name '*.deps' | xargs rm -rf
find -name '*.libs' | xargs rm -rf
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/
find -name 'ui_*.h' | xargs rm -f
find -name 'CMakeFiles' | xargs rm -rf
rm -f stamp-h1
install: build install-stamp
install-stamp:
@ -78,44 +52,34 @@ install-stamp:
dh_testroot
dh_prep
dh_installdirs
$(MAKE) install 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
$(MAKE) install/fast DESTDIR=$(CURDIR)/debian/tmp/freecad
# install the core system
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/lib/FreeCAD.so usr/lib/freecad/lib
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/lib usr/lib/freecad
dh_install -pfreecad debian/tmp/freecad/usr/lib/freecad/Mod usr/lib/freecad
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
# install the modules
$(foreach MODULE,$(MODULES), \
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 headers
#dh_install -pfreecad-dev debian/tmp/freecad/usr/include/* usr/include
# install the help system
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
override_dh_compress:

View 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

View File

@ -1,2 +0,0 @@
libGL 1 libgl1-mesa-glx (>= 7.7.1-1)
libSoQt4 20 libsoqt4-20 (>= 1.4.2~svn20090224)

View File

@ -1 +1 @@
3.0 (quilt)
1.0

View File

@ -16,68 +16,36 @@
# http://www.grymoire.com/Unix/Sed.html
# global settings
REV_FILE=./revision.m4
TMP_PATH=/tmp
MAJ=0
MIN=12
ALIAS="Vulcan"
MIN=13
# go to root directory
CUR_DIR=$PWD
verz=`dirname $(readlink -f ${0})`
cd $verz && cd ..
# let's import OLD_REV (if there)
if [ -f ./.last_revision ]; then
. ./.last_revision
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`
# http://blog.marcingil.com/2011/11/creating-build-numbers-using-git-commits/
if git log -1 >/dev/null 2>&1; then
REV=`git rev-list HEAD | wc -l | sed -e 's/ *//g' | xargs -n1 printf %04d`
else
REV=0
LCD=""
URL=""
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
# Prepare source tarball and unpack it in build directory
cd $CUR_DIR
make dist
make dist-git
cd $verz && cd ..
rm -rf $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
tar -xzf freecad_$MAJ.$MIN.$REV.orig.tar.gz
mv FreeCAD-$MAJ.$MIN.$REV freecad-$MAJ.$MIN.$REV
cd freecad-$MAJ.$MIN.$REV
rm -rf src/CXX
rm -rf src/zipios++
#rm -rf src/CXX
#rm -rf src/zipios++
# Prepare debian folder and set the revision number in debian/changelog
# for package versioning

View File

@ -42,9 +42,13 @@
#include "utilities.h"
#include <Standard_Version.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepTools.hxx>
#if OCC_VERSION_HEX >= 0x060600
#include <BRepClass3d.hxx>
#endif
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shell.hxx>
@ -159,7 +163,11 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a
// get 2 shells
TopoDS_Solid solid = TopoDS::Solid( aShape );
#if OCC_VERSION_HEX >= 0x060600
TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid );
#else
TopoDS_Shell outerShell = BRepTools::OuterShell( solid );
#endif
TopoDS_Shape innerShell;
int nbShells = 0;
for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells )

View File

@ -1008,7 +1008,10 @@ void Application::initTypes(void)
App ::PropertyPercent ::init();
App ::PropertyEnumeration ::init();
App ::PropertyIntegerList ::init();
App ::PropertyIntegerSet ::init();
App ::PropertyMap ::init();
App ::PropertyString ::init();
App ::PropertyUUID ::init();
App ::PropertyFont ::init();
App ::PropertyStringList ::init();
App ::PropertyLink ::init();
@ -1213,7 +1216,8 @@ void Application::processCmdLineFiles(void)
else if (File.hasExtension("py")) {
try {
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__)
Base::Interpreter().runFile(File.filePath().c_str(),true);
}

View File

@ -64,6 +64,10 @@ recompute path. Also enables more complicated dependencies beyond trees.
#include <boost/graph/graphviz.hpp>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/unordered_set.hpp>
#include <QCoreApplication>
#include <QCryptographicHash>
#include "Document.h"
@ -433,9 +437,42 @@ unsigned int Document::getMaxUndoStackSize(void)const
void Document::onChanged(const Property* prop)
{
// the Name property is a label for display purposes
if (prop == &Label)
if (prop == &Label) {
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)
{
@ -525,7 +562,7 @@ Document::Document(void)
#endif
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(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,Prop_ReadOnly,"Date of creation");
ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,Prop_None,0);
@ -537,19 +574,16 @@ Document::Document(void)
// create the uuid for the document
Base::Uuid id;
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
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");
// create transient directory
std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName();
Base::FileInfo TransDir(basePath + "_Doc_" + id.getValue());
if (!TransDir.exists())
TransDir.createDirectory();
ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,Prop_Transient,
// this creates and sets 'TransientDir' in onChanged()
ADD_PROPERTY_TYPE(TransientDir,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),
"Transient directory, where the files live while the document is open");
Uid.touch();
}
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
// 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.
// 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.
Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
// Call before decrementing the reference counter, otherwise a heap error can occur
@ -586,6 +620,19 @@ Document::~Document()
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
//--------------------------------------------------------------------------
@ -623,12 +670,7 @@ void Document::Restore(Base::XMLReader &reader)
std::string FilePath = FileName.getValue();
std::string DocLabel = Label.getValue();
// remove previous Transient directory
Base::FileInfo TransDir(TransientDir.getValue());
TransDir.deleteDirectoryRecursive();
// read the Document Properties
// read the Document Properties, when reading in Uid the transient directory gets renamed automatically
PropertyContainer::Restore(reader);
// 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());
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"
if ( scheme == 2 ) {
// read the feature types
@ -769,8 +803,8 @@ Document::readObjects(Base::XMLReader& reader)
reader.addName(name.c_str(), obj->getNameInDocument());
}
}
catch (Base::Exception&) {
Base::Console().Message("Cannot create object '%s'\n", name.c_str());
catch (const Base::Exception& e) {
Base::Console().Error("Cannot create object '%s': (%s)\n", name.c_str(), e.what());
}
}
reader.readEndElement("Objects");
@ -857,6 +891,18 @@ void Document::exportGraphviz(std::ostream& out)
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
bool Document::save (void)
{
@ -1090,6 +1136,58 @@ std::vector<App::DocumentObject*> Document::getInList(const DocumentObject* me)
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)
{
d->VertexObjectList.clear();
@ -1119,21 +1217,6 @@ void Document::recompute()
// updates the dependency graph
_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;
DependencyList::out_edge_iterator j, jend;

View File

@ -133,6 +133,7 @@ public:
//void saveAs (const char* Name);
/// Save the document to the file in Property Path
bool save (void);
bool saveAs(const char* file);
/// Restore the document from the file in Property Path
void restore (void);
void exportObjects(const std::vector<App::DocumentObject*>&, std::ostream&);
@ -264,6 +265,10 @@ public:
bool checkOnCycle(void);
/// get a list of all objects linking to the given object
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
//void setChanged(DocumentObject* change);
//@}
@ -303,6 +308,7 @@ protected:
void _clearRedos();
/// refresh the internal dependency graph
void _rebuildDependencyList(void);
std::string getTransientDirectoryName(const std::string& uuid, const std::string& filename) const;
private:

View File

@ -38,6 +38,15 @@ namespace App
class Document;
class DocumentObjectPy;
enum ObjectStatus {
Touch = 0,
Error = 1,
New = 2,
Recompute = 3,
Restore = 4,
Expand = 16
};
/** Return object for feature execution
*/
class AppExport DocumentObjectExecReturn
@ -105,6 +114,8 @@ public:
virtual App::DocumentObjectExecReturn *recompute(void);
/// return the status bits
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
@ -129,7 +140,7 @@ public:
/** Called in case of loosing a link
* 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
*additional or different behavior.
*/
@ -168,6 +179,7 @@ protected:
* 5 - reserved
* 6 - reserved
* 7 - reserved
* 16 - object is marked as 'expanded' in the tree view
*/
std::bitset<32> StatusBits;

View File

@ -101,7 +101,7 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
}
catch (Py::Exception&) {
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&) {
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&) {
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&) {
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&) {
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&) {
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&) {
Base::PyException e; // extract the Python error text
Base::Console().Error("%s\n", e.what());
e.ReportException();
}
}

View File

@ -15,12 +15,17 @@
</Documentation>
<Methode Name="save">
<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>
</Methode>
<Methode Name="restore">
<Documentation>
<UserDocu>Restore the document from disc</UserDocu>
<UserDocu>Restore the document from disk</UserDocu>
</Documentation>
</Methode>
<Methode Name="exportGraphviz">

View File

@ -69,6 +69,25 @@ PyObject* DocumentPy::save(PyObject * args)
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)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C

View File

@ -67,6 +67,7 @@ DocumentObjectExecReturn *FeaturePythonImp::execute()
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
std::stringstream str;
str << object->Label.getValue() << ": " << e.what();
return new App::DocumentObjectExecReturn(str.str());
@ -104,8 +105,7 @@ void FeaturePythonImp::onChanged(const Property* prop)
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Error("FeaturePython::onChanged (%s): %s\n",
object->Label.getValue(), e.what());
e.ReportException();
}
}

View File

@ -61,7 +61,7 @@ public:
*/
virtual unsigned int getMemSize (void) const {
// 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

View File

@ -24,6 +24,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
# include <sstream>
#endif
@ -35,12 +36,13 @@
#include <Base/Stream.h>
#include <Base/Console.h>
#include <Base/PyObjectBase.h>
#include <Base/Uuid.h>
#include "PropertyFile.h"
#include "Document.h"
#include "PropertyContainer.h"
#include "DocumentObject.h"
#define new DEBUG_CLIENTBLOCK
using namespace App;
using namespace Base;
using namespace std;
@ -53,6 +55,7 @@ using namespace std;
TYPESYSTEM_SOURCE(App::PropertyFileIncluded , App::Property);
PropertyFileIncluded::PropertyFileIncluded()
{
@ -63,17 +66,45 @@ PropertyFileIncluded::~PropertyFileIncluded()
// clean up
if (!_cValue.empty()) {
Base::FileInfo file(_cValue.c_str());
file.setPermissions(Base::FileInfo::ReadWrite);
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 path;
PropertyContainer *co = getContainer();
if (co->isDerivedFrom(DocumentObject::getClassTypeId()))
return dynamic_cast<DocumentObject*>(co)->getDocument()->TransientDir.getValue();
if (co->isDerivedFrom(DocumentObject::getClassTypeId())) {
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
@ -97,34 +128,40 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
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)
Base::FileInfo value(_cValue);
std::string pathAct = value.dirPath();
if (value.exists())
if (value.exists()) {
value.setPermissions(Base::FileInfo::ReadWrite);
value.deleteFile();
}
// if a special name given, use this instead
if (sName) {
Base::FileInfo ExtraName(path + "/" + sName);
if (ExtraName.exists() ) {
Base::FileInfo fi(pathTrans + "/" + sName);
if (fi.exists()) {
// 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;
do {
i++;
std::stringstream str;
str << path << "/" << sName << i;
ExtraName.setFile(str.str());
str << dir << "/" << fnp << i;
if (!ext.empty())
str << "." << ext;
fi.setFile(str.str());
}
while (ExtraName.exists());
_cValue = ExtraName.filePath();
_BaseFileName = ExtraName.fileName();
while (fi.exists());
_cValue = fi.filePath();
_BaseFileName = fi.fileName();
}
else {
_cValue = path + "/" + sName;
_cValue = pathTrans + "/" + sName;
_BaseFileName = sName;
}
}
@ -133,39 +170,61 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
_BaseFileName = file.fileName();
}
// if the files is already in transient dir of the document, just use it
if (path == pathTrans) {
// The following applies only on files that are inside the transient
// 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());
//assert(done);
if (!done) {
std::stringstream str;
str << "Cannot rename file " << file.filePath() << " to " << _cValue;
throw Base::Exception(str.str());
}
// make the file read-only
Base::FileInfo dst(_cValue);
dst.setPermissions(Base::FileInfo::ReadOnly);
}
// otherwise copy from origin location
else {
// if file already exists in transient dir make a new unique name
Base::FileInfo fi(_cValue);
if (fi.exists()) {
Base::FileInfo fi2(Base::FileInfo::getTempFileName());
std::stringstream str;
str << fi.dirPath() << "/" << fi2.fileNamePure();
// if a file with this name already exists search for a new one
std::string dir = fi.dirPath();
std::string fnp = fi.fileNamePure();
std::string ext = fi.extension(false);
int i=0;
do {
i++;
std::stringstream str;
str << dir << "/" << fnp << i;
if (!ext.empty())
str << "." << ext;
Base::FileInfo fi3(str.str());
_cValue = fi3.filePath();
_BaseFileName = fi3.fileName();
fi.setFile(str.str());
}
while (fi.exists());
_cValue = fi.filePath();
_BaseFileName = fi.fileName();
}
bool done = file.copyTo(_cValue.c_str());
//assert(done);
if (!done) {
std::stringstream str;
str << "Cannot copy file from " << file.filePath() << " to " << _cValue;
throw Base::Exception(str.str());
}
// make the file read-only
Base::FileInfo dst(_cValue);
dst.setPermissions(Base::FileInfo::ReadOnly);
}
hasSetValue();
@ -180,7 +239,7 @@ const char* PropertyFileIncluded::getValue(void) const
PyObject *PropertyFileIncluded::getPyObject(void)
{
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;
}
@ -201,7 +260,7 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
}
else if (PyTuple_Check(value)) {
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* name = PyTuple_GetItem(value,1);
@ -220,9 +279,9 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
fileStr = PyString_AsString(FileName);
}
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;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
// decoding name
@ -235,19 +294,18 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
nameStr = PyString_AsString(FileName);
}
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;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
setValue(fileStr.c_str(),nameStr.c_str());
return;
}
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;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
// assign the string
@ -256,31 +314,41 @@ void PropertyFileIncluded::setPyObject(PyObject *value)
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 (!_cValue.empty()) {
Base::FileInfo file(_cValue.c_str());
writer.Stream() << writer.ind() << "<FileIncluded data=\"" <<
file.fileName() << "\">" << std::endl;
writer.Stream() << writer.ind() << "<FileIncluded data=\""
<< file.fileName() << "\">" << std::endl;
// write the file in the XML stream
writer.incInd();
writer.insertBinFile(_cValue.c_str());
writer.decInd();
writer.Stream() << writer.ind() <<"</FileIncluded>" << endl;
}
else
else {
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>" << std::endl;
}
}
else {
// instead initiate an extra file
if (!_cValue.empty()) {
Base::FileInfo file(_cValue.c_str());
writer.Stream() << writer.ind() << "<FileIncluded file=\"" <<
writer.addFile(file.fileName().c_str(), this) << "\"/>" << std::endl;
writer.Stream() << writer.ind() << "<FileIncluded file=\""
<< writer.addFile(file.fileName().c_str(), this) << "\"/>" << std::endl;
}
else
else {
writer.Stream() << writer.ind() << "<FileIncluded file=\"\"/>" << std::endl;
}
}
}
void PropertyFileIncluded::Restore(Base::XMLReader &reader)
{
@ -307,6 +375,9 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
reader.readBinFile(_cValue.c_str());
reader.readEndElement("FileIncluded");
_BaseFileName = file;
// set read-only after restoring the file
Base::FileInfo fi(_cValue.c_str());
fi.setPermissions(Base::FileInfo::ReadOnly);
hasSetValue();
}
}
@ -315,9 +386,12 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
{
Base::ifstream from(Base::FileInfo(_cValue.c_str()));
if (!from)
throw Base::Exception("PropertyFileIncluded::SaveDocFile() "
"File in document transient dir deleted");
if (!from) {
std::stringstream str;
str << "PropertyFileIncluded::SaveDocFile(): "
<< "File '" << _cValue << "' in transient directory doesn't exist.";
throw Base::Exception(str.str());
}
// copy plain data
unsigned char c;
@ -329,10 +403,14 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
{
Base::ofstream to(Base::FileInfo(_cValue.c_str()));
if (!to)
throw Base::Exception("PropertyFileIncluded::RestoreDocFile() "
"File in document transient dir deleted");
Base::FileInfo fi(_cValue.c_str());
Base::ofstream to(fi);
if (!to) {
std::stringstream str;
str << "PropertyFileIncluded::RestoreDocFile(): "
<< "File '" << _cValue << "' in transient directory doesn't exist.";
throw Base::Exception(str.str());
}
// copy plain data
aboutToSetValue();
@ -341,6 +419,9 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
to.put((const char)c);
}
to.close();
// set read-only after restoring the file
fi.setPermissions(Base::FileInfo::ReadOnly);
hasSetValue();
}
@ -351,18 +432,39 @@ Property *PropertyFileIncluded::Copy(void) const
// remember the base name
prop->_BaseFileName = _BaseFileName;
if (!_cValue.empty()) {
Base::FileInfo file(_cValue);
if (file.exists()) {
// create a new name in the document transient directory
Base::FileInfo NewName(Base::FileInfo::getTempFileName(file.fileName().c_str(),file.dirPath().c_str()));
NewName.deleteFile();
// move the file
bool done = file.renameFile(NewName.filePath().c_str());
assert(done);
Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName()));
if (this->StatusBits.test(10)) {
// rename the file
bool done = file.renameFile(newName.filePath().c_str());
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
Base::Console().Log("Copy this=%p Before=%s After=%s\n",prop,prop->_cValue.c_str(),NewName.filePath().c_str());
prop->_cValue = 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();
// make backup files writable to avoid copying them again on undo/redo
newName.setPermissions(Base::FileInfo::ReadWrite);
}
return prop;
@ -371,26 +473,65 @@ Property *PropertyFileIncluded::Copy(void) const
void PropertyFileIncluded::Paste(const Property &from)
{
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)
file.deleteFile();
const PropertyFileIncluded &fileInc = dynamic_cast<const PropertyFileIncluded&>(from);
Base::FileInfo fi(_cValue);
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
_BaseFileName = fileInc._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);
_BaseFileName = prop._BaseFileName;
}
else
_cValue.clear();
hasSetValue();
}
unsigned int PropertyFileIncluded::getMemSize (void) const
{
unsigned int mem = Property::getMemSize();
mem += _cValue.size();
mem += _BaseFileName.size();
return mem;
}
//**************************************************************************
// PropertyFile

View File

@ -95,9 +95,7 @@ public:
virtual Property *Copy(void) const;
virtual void Paste(const Property &from);
// get the transient path if the property is in a DocumentObject
std::string getDocTransientPath(void) const;
virtual unsigned int getMemSize (void) const;
/** get a temp file name in the transient path of the document.
* Using this file for new Version of the file and set
@ -107,8 +105,14 @@ public:
std::string getExchangeTempFile(void) const;
protected:
std::string _cValue;
std::string _BaseFileName;
// get the transient path if the property is in a DocumentObject
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;
};

View File

@ -117,7 +117,7 @@ void PropertyVector::setPyObject(PyObject *value)
else if (PyInt_Check(item))
cVec.x = (float)PyInt_AsLong(item);
else
throw Base::Exception("Not allowed type used in tuple (float expected)...");
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
// y
item = PyTuple_GetItem(value,1);
if (PyFloat_Check(item))
@ -125,7 +125,7 @@ void PropertyVector::setPyObject(PyObject *value)
else if (PyInt_Check(item))
cVec.y = (float)PyInt_AsLong(item);
else
throw Base::Exception("Not allowed type used in tuple (float expected)...");
throw Base::TypeError("Not allowed type used in tuple (float expected)...");
// z
item = PyTuple_GetItem(value,2);
if (PyFloat_Check(item))
@ -133,13 +133,13 @@ void PropertyVector::setPyObject(PyObject *value)
else if (PyInt_Check(item))
cVec.z = (float)PyInt_AsLong(item);
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 );
}
else {
std::string error = std::string("type must be 'Vector' or tuple of three floats, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -271,7 +271,7 @@ void PropertyVectorList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'Vector' or list of 'Vector', not ");
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))
cMatrix[x][y] = (double)PyInt_AsLong(item);
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 {
std::string error = std::string("type must be 'Matrix' or tuple of 16 float or int, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -520,7 +520,7 @@ void PropertyPlacement::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'Matrix' or 'Placement', not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}

View File

@ -110,7 +110,7 @@ void PropertyLink::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'DocumentObject' or 'NoneType', not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -257,7 +257,7 @@ void PropertyLinkSub::setPyObject(PyObject *value)
else {
std::string error = std::string("type of first element in tuple must be 'DocumentObject', not ");
error += tup[0].ptr()->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
else if(Py_None == value) {
@ -266,7 +266,7 @@ void PropertyLinkSub::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'DocumentObject', 'NoneType' or ('DocumentObject',['String',]) not ");
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))) {
std::string error = std::string("type in list must be 'DocumentObject', not ");
error += (*item)->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
@ -424,7 +424,7 @@ void PropertyLinkList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -609,7 +609,7 @@ void PropertyLinkSubList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}

View File

@ -108,7 +108,7 @@ std::string PropertyPythonObject::toString() const
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::toString: %s\n", e.what());
e.ReportException();
}
return repr;
@ -139,7 +139,7 @@ void PropertyPythonObject::fromString(const std::string& repr)
}
catch (Py::Exception&) {
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&) {
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&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what());
e.ReportException();
}
saveObject(writer);
@ -350,7 +350,7 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader)
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what());
e.ReportException();
this->object = Py::None();
load_failed = true;
}

View File

@ -98,7 +98,7 @@ void PropertyInteger::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -211,7 +211,7 @@ void PropertyPath::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be str or unicode, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
// assign the path
@ -472,7 +472,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
long i=0;
while(*(plEnums++) != NULL)i++;
if (val < 0 || i <= val)
throw Py::ValueError("Out of range");
throw Base::ValueError("Out of range");
PropertyInteger::setValue(val);
}
}
@ -481,7 +481,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
if (_EnumArray && isPartOf(str))
setValue(PyString_AsString (value));
else
throw Py::ValueError("not part of the enum");
throw Base::ValueError("not part of the enum");
}
else if (PyList_Check(value)) {
Py_ssize_t nSize = PyList_Size(value);
@ -493,7 +493,7 @@ void PropertyEnumeration::setPyObject(PyObject *value)
if (!PyString_Check(item)) {
std::string error = std::string("type in list must be str, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
values[i] = PyString_AsString(item);
}
@ -505,10 +505,33 @@ void PropertyEnumeration::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int or str, not ");
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
@ -559,7 +582,7 @@ void PropertyIntegerConstraint::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int, not ");
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)) {
std::string error = std::string("type in list must be int, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
values[i] = PyInt_AsLong(item);
}
@ -667,7 +690,7 @@ void PropertyIntegerList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int or list of int, not ");
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)) {
std::string error = std::string("type in list must be int, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
values.insert(PyInt_AsLong(item));
}
@ -795,7 +818,7 @@ void PropertyIntegerSet::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int or list of int, not ");
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"));
}
reader.readEndElement("IntegerList");
reader.readEndElement("IntegerSet");
//assignment
setValues(values);
@ -905,7 +928,7 @@ void PropertyFloat::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be float or int, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -999,7 +1022,7 @@ void PropertyFloatConstraint::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be float, not ");
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)) {
std::string error = std::string("type in list must be float, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
values[i] = (float) PyFloat_AsDouble(item);
@ -1086,7 +1109,7 @@ void PropertyFloatList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be float or list of float, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -1217,7 +1240,7 @@ void PropertyString::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be str or unicode, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
// assign the string
@ -1322,11 +1345,18 @@ void PropertyUUID::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be a str, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
try {
// 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
@ -1465,7 +1495,7 @@ void PropertyStringList::setPyObject(PyObject *value)
else {
std::string error = std::string("type in list must be str or unicode, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -1477,7 +1507,7 @@ void PropertyStringList::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be str or list of str, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -1625,7 +1655,7 @@ void PropertyMap::setPyObject(PyObject *value)
else {
std::string error = std::string("type of the key need to be a string, not");
error += key->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
// check on the item:
@ -1641,7 +1671,7 @@ void PropertyMap::setPyObject(PyObject *value)
else {
std::string error = std::string("type in list must be string or unicode, not ");
error += item->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -1650,7 +1680,7 @@ void PropertyMap::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be a dict object");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -1764,7 +1794,7 @@ void PropertyBool::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be bool, not ");
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))
cCol.r = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,1);
if (PyFloat_Check(item))
cCol.g = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,2);
if (PyFloat_Check(item))
cCol.b = (float)PyFloat_AsDouble(item);
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) {
PyObject* item;
@ -1894,22 +1924,22 @@ void PropertyColor::setPyObject(PyObject *value)
if (PyFloat_Check(item))
cCol.r = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,1);
if (PyFloat_Check(item))
cCol.g = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,2);
if (PyFloat_Check(item))
cCol.b = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,3);
if (PyFloat_Check(item))
cCol.a = (float)PyFloat_AsDouble(item);
else
throw Base::Exception("Type in tuple must be float");
throw Base::TypeError("Type in tuple must be float");
}
else if (PyLong_Check(value)) {
cCol.setPackedValue(PyLong_AsUnsignedLong(value));
@ -1917,7 +1947,7 @@ void PropertyColor::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be int or tuple of float, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
setValue( cCol );
@ -2050,7 +2080,7 @@ void PropertyColorList::setPyObject(PyObject *value)
else {
std::string error = std::string("not allowed type, ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}
@ -2201,7 +2231,7 @@ void PropertyMaterial::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be 'Material', not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
}

View File

@ -183,6 +183,9 @@ public:
virtual void Save (Base::Writer &writer) const;
virtual void Restore(Base::XMLReader &reader);
virtual Property *Copy(void) const;
virtual void Paste(const Property &from);
private:
bool _CustomEnum;
const char** _EnumArray;

View File

@ -102,11 +102,11 @@ void PropertyLength::setPyObject(PyObject *value)
else {
std::string error = std::string("type must be float or int, not ");
error += value->ob_type->tp_name;
throw Py::TypeError(error);
throw Base::TypeError(error);
}
if (val < 0.0f)
throw Py::ValueError("value must be nonnegative");
throw Base::ValueError("value must be nonnegative");
setValue(val);
#endif

View File

@ -24,11 +24,11 @@
<UserDocu>Returns all descentences</UserDocu>
</Documentation>
</Methode>
<Attribute Name="Type" ReadOnly="true">
<Attribute Name="TypeId" ReadOnly="true">
<Documentation>
<UserDocu>Is the type of the FreeCAD object with module domain</UserDocu>
</Documentation>
<Parameter Name="Type" Type="String" />
<Parameter Name="TypeId" Type="String" />
</Attribute>
<Attribute Name="Module" ReadOnly="true">
<Documentation>

View File

@ -68,7 +68,7 @@ PyObject* BaseClassPy::getAllDerivedFrom(PyObject *args)
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()));
}
@ -78,8 +78,15 @@ Py::Int BaseClassPy::getModule(void) const
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;
}

View File

@ -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)
#include <stdexcept>
#include <iostream>

View File

@ -48,7 +48,7 @@ public:
Exception &operator=(const Exception &inst);
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 std::string& sMessage);
@ -206,6 +206,70 @@ public:
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)
{

View File

@ -26,6 +26,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
# include <cassert>
# include <cstdio>
# include <cstdlib>
@ -51,10 +52,20 @@
#include <sys/stat.h>
#include <cstdio>
#define new DEBUG_CLIENTBLOCK
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
@ -188,22 +199,13 @@ std::string FileInfo::getTempFileName(const char* FileName, const char* Path)
void FileInfo::setFile(const char* name)
{
std::string result;
const char *It=name;
while(*It != '\0') {
switch(*It)
{
case '\\':
result += "/";
break;
default:
result += *It;
}
It++;
if (!name) {
FileName.clear();
return;
}
FileName = result;
FileName = name;
std::replace(FileName.begin(), FileName.end(), '\\', '/');
}
std::string FileInfo::filePath () const
@ -271,9 +273,9 @@ bool FileInfo::exists () const
{
#if defined (FC_OS_WIN32)
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)
return access(FileName.c_str(),0) == 0;
return access(FileName.c_str(),F_OK) == 0;
#endif
}
@ -281,9 +283,9 @@ bool FileInfo::isReadable () const
{
#if defined (FC_OS_WIN32)
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)
return access(FileName.c_str(),4) == 0;
return access(FileName.c_str(),R_OK) == 0;
#endif
}
@ -291,9 +293,29 @@ bool FileInfo::isWritable () const
{
#if defined (FC_OS_WIN32)
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)
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
}
@ -428,7 +450,6 @@ bool FileInfo::renameFile(const char* NewName)
#else
# error "FileInfo::renameFile() not implemented for this platform!"
#endif
setFile(NewName);
return res;
}
@ -482,13 +503,18 @@ bool FileInfo::deleteDirectoryRecursive(void) const
std::vector<Base::FileInfo> List = getDirectoryContent();
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();
else if(It->isFile())
}
else if (It->isFile()) {
It->setPermissions(FileInfo::ReadWrite);
It->deleteFile();
else
}
else {
Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!");
}
}
return deleteDirectory();
}

View File

@ -42,6 +42,12 @@ namespace Base
class BaseExport FileInfo
{
public:
enum Permissions {
WriteOnly = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x03,
};
/// Constrction
FileInfo (const char* _FileName="");
FileInfo (const std::string &_FileName);
@ -89,6 +95,8 @@ public:
bool isReadable () const;
/// Checks if the file exist and is writable
bool isWritable () const;
/// Tries to set the file permisson
bool setPermissions (Permissions);
/// Checks if it is a file (not a direrctory)
bool isFile () const;
/// Checks if it is a directory (not a file)
@ -109,7 +117,7 @@ public:
std::vector<Base::FileInfo> getDirectoryContent(void) const;
/// Delete an empty directory
bool deleteDirectory(void) const;
/// Delete a directory and all its content
/// Delete a directory and all its content.
bool deleteDirectoryRecursive(void) const;
//@}

View File

@ -71,9 +71,18 @@ PyException::PyException(void)
_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)
}
void PyException::ReportException (void) const
{
Base::Console().Error("%s%s: %s\n",
_stackTrace.c_str(), _errorType.c_str(), what());
}
// ---------------------------------------------------------

View File

@ -54,11 +54,12 @@ class BaseExport PyException : public Exception
public:
/// constructor does the whole job
PyException(void);
~PyException() throw() {}
~PyException() throw();
/// this function returns the stack trace
const std::string &getStackTrace(void) const {return _stackTrace;}
const std::string &getErrorType(void) const {return _errorType;}
void ReportException (void) const;
protected:
std::string _stackTrace;

View File

@ -38,9 +38,16 @@ using namespace Base;
std::string RotationPy::representation(void) const
{
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;
str << "Quaternion (";
str << ptr->getValue()[0] << ","<< ptr->getValue()[1] << "," << ptr->getValue()[2] << "," << ptr->getValue()[3];
str << "Rotation (";
str << (std::string)q0.repr() << ", "
<< (std::string)q1.repr() << ", "
<< (std::string)q2.repr() << ", "
<< (std::string)q3.repr();
str << ")";
return str.str();

View File

@ -40,9 +40,12 @@ using namespace Base;
std::string VectorPy::representation(void) const
{
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;
str << "Vector (";
str << ptr->x << ", "<< ptr->y << ", "<< ptr->z;
str << (std::string)x.repr() << ", "<< (std::string)y.repr() << ", "<< (std::string)z.repr();
str << ")";
return str.str();

View File

@ -1,7 +1,7 @@
// Version Number
#define FCVersionMajor "0"
#define FCVersionMinor "13"
#define FCVersionMinor "14"
#define FCVersionName "Vulcan"
// test: $Format:Hash (%H), Date: %ci$
#define FCRevision "$WCREV$" //Highest committed revision number

View File

@ -41,8 +41,11 @@
# include <QGLFramebufferObject>
#endif
# include <QSessionManager>
# include <QTextStream>
#endif
#include <boost/interprocess/sync/file_lock.hpp>
// FreeCAD Base header
#include <Base/Console.h>
@ -336,6 +339,18 @@ Application::Application(bool GUIenabled)
("User parameter:BaseApp/Preferences/Units");
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
Base::PyGILStateLocker lock;
PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods,
@ -1739,9 +1754,24 @@ void Application::runApplication(void)
Base::Console().Log("Init: Entering event loop\n");
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();
if (ret == systemExit)
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&) {
Base::Console().Message("System exit\n");
@ -1756,3 +1786,66 @@ void Application::runApplication(void)
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:
}
}

View File

@ -157,6 +157,7 @@ public:
/// true when the application shuting down
bool isClosing(void);
void checkForPreviousCrashes();
/** @name workbench handling */
//@{
@ -210,6 +211,7 @@ public:
PYFUNCDEF_S(sSendActiveView);
PYFUNCDEF_S(sGetMainWindow);
PYFUNCDEF_S(sUpdateGui);
PYFUNCDEF_S(sUpdateLocale);
PYFUNCDEF_S(sGetLocale);

View File

@ -83,6 +83,9 @@ PyMethodDef Application::Methods[] = {
{"addIcon", (PyCFunction) Application::sAddIcon, 1,
"addIcon(string, string or list) -> None\n\n"
"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() -> None\n\n"
"Update the main window and all its windows"},
@ -418,6 +421,22 @@ PyObject* Application::sSendActiveView(PyObject * /*self*/, PyObject *args,PyObj
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*/)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C

View File

@ -84,7 +84,7 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
// up the inheritance hierarchy.
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
// 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
const SoType type(ev->getTypeId());

View File

@ -86,7 +86,7 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev)
if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
#else
// 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
#endif

View File

@ -3,6 +3,7 @@
if(WIN32)
add_definitions(-DFCGui -DQIIS_MAKEDLL)
endif(WIN32)
if (FREECAD_USE_3DCONNEXION)
add_definitions(-D_USE_3DCONNEXION_SDK)
endif(FREECAD_USE_3DCONNEXION)
@ -59,6 +60,30 @@ IF(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(PythonWorkbenchPy)
generate_from_xml(ViewProviderPy)
@ -97,8 +122,11 @@ set(Gui_MOC_HDRS
CallTips.h
CombiView.h
Control.h
Clipping.h
DemoMode.h
DownloadDialog.h
DownloadItem.h
DownloadManager.h
DlgActionsImp.h
DlgActivateWindowImp.h
DlgCommandsImp.h
@ -186,6 +214,7 @@ fc_wrap_cpp(Gui_MOC_SRCS ${Gui_MOC_HDRS})
SET(Gui_UIC_SRCS
AboutApplication.ui
Clipping.ui
DemoMode.ui
DlgActions.ui
DlgActivateWindow.ui
@ -220,6 +249,8 @@ SET(Gui_UIC_SRCS
DlgTreeWidget.ui
DlgLocationAngle.ui
DlgLocationPos.ui
DownloadManager.ui
DownloadItem.ui
MouseButtons.ui
SceneInspector.ui
InputVector.ui
@ -260,6 +291,7 @@ SOURCE_GROUP("Command" FILES ${Command_SRCS})
# The dialog sources
SET(Dialog_CPP_SRCS
Clipping.cpp
DemoMode.cpp
DlgActivateWindowImp.cpp
DlgDisplayPropertiesImp.cpp
@ -282,9 +314,12 @@ SET(Dialog_CPP_SRCS
TextureMapping.cpp
Transform.cpp
DownloadDialog.cpp
DownloadItem.cpp
DownloadManager.cpp
)
SET(Dialog_HPP_SRCS
Clipping.h
DemoMode.h
DlgActivateWindowImp.h
DlgDisplayPropertiesImp.h
@ -307,17 +342,22 @@ SET(Dialog_HPP_SRCS
TextureMapping.h
Transform.h
DownloadDialog.h
DownloadItem.h
DownloadManager.h
)
SET(Dialog_SRCS
${Dialog_CPP_SRCS}
${Dialog_HPP_SRCS}
AboutApplication.ui
Clipping.ui
DemoMode.ui
DlgActivateWindow.ui
DlgAuthorization.ui
DlgDisplayProperties.ui
DlgInputDialog.ui
DlgLocationAngle.ui
DlgLocationPos.ui
DlgMacroExecute.ui
DlgRunExternal.ui
DlgMacroRecord.ui
@ -327,6 +367,8 @@ SET(Dialog_SRCS
DlgProjectUtility.ui
DlgTipOfTheDay.ui
DlgTreeWidget.ui
DownloadManager.ui
DownloadItem.ui
MouseButtons.ui
InputVector.ui
Placement.ui
@ -884,7 +926,13 @@ else(WIN32)
INSTALL(TARGETS FreeCADGui
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}
)
endif(WIN32)

315
src/Gui/Clipping.cpp Normal file
View 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
View 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
View 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>

View File

@ -581,6 +581,12 @@ void Command::applyCommandData(Action* action)
action->setWhatsThis(QCoreApplication::translate(
this->className(), sToolTipText, 0,
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

View File

@ -841,7 +841,6 @@ void StdCmdCopy::activated(int iMsg)
{
bool done = getGuiApplication()->sendMsgToActiveView("Copy");
if (!done) {
WaitCursor wc;
QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection();
QClipboard* cb = QApplication::clipboard();
cb->setMimeData(mimeData);
@ -910,59 +909,54 @@ StdCmdDuplicateSelection::StdCmdDuplicateSelection()
void StdCmdDuplicateSelection::activated(int iMsg)
{
App::Document* act = App::GetApplication().getActiveDocument();
if (!act)
return; // no active document found
Gui::Document* doc = Gui::Application::Instance->getDocument(act);
std::vector<Gui::SelectionSingleton::SelObj> sel = Gui::Selection().getCompleteSelection();
std::vector<SelectionSingleton::SelObj> sel = Selection().getCompleteSelection();
std::map< App::Document*, std::vector<App::DocumentObject*> > objs;
for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
if (!it->pObject)
continue; // should actually not happen
// 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();
}
if (it->pObject && it->pObject->getDocument()) {
objs[it->pObject->getDocument()].push_back(it->pObject);
}
}
Gui::Document* parent = Gui::Application::Instance->getDocument(it->pObject->getDocument());
if (!parent || !doc)
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
if (objs.empty())
return;
// get the properties of the view provider
props.clear();
view->getPropertyMap(props);
copy_props.clear();
copy_view->getPropertyMap(copy_props);
for (std::map<std::string,App::Property*>::iterator jt = props.begin(); jt != props.end(); ++jt) {
std::map<std::string,App::Property*>::iterator kt;
kt = copy_props.find(jt->first);
if (kt != copy_props.end()) {
std::auto_ptr<App::Property> data(jt->second->Copy());
if (data.get()) {
kt->second->Paste(*data);
Base::FileInfo fi(Base::FileInfo::getTempFileName());
{
std::vector<App::DocumentObject*> sel; // selected
std::vector<App::DocumentObject*> all; // object sub-graph
for (std::map< App::Document*, std::vector<App::DocumentObject*> >::iterator it = objs.begin(); it != objs.end(); ++it) {
std::vector<App::DocumentObject*> dep = it->first->getDependencyList(it->second);
sel.insert(sel.end(), it->second.begin(), it->second.end());
all.insert(all.end(), dep.begin(), dep.end());
}
if (all.size() > sel.size()) {
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)
@ -1032,11 +1026,45 @@ void StdCmdDelete::activated(int iMsg)
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(*it);
std::vector<Gui::SelectionObject> sel = rSel.getSelectionEx((*it)->getName());
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");
for (std::vector<Gui::SelectionObject>::iterator ft = sel.begin(); ft != sel.end(); ++ft) {
Gui::ViewProvider* vp = pGuiDoc->getViewProvider(ft->getObject());
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()))
doCommand(Doc,"App.getDocument(\"%s\").removeObject(\"%s\")"
,(*it)->getName(), ft->getFeatName());
@ -1046,6 +1074,7 @@ void StdCmdDelete::activated(int iMsg)
}
}
}
}
bool StdCmdDelete::isActive(void)
{

View File

@ -38,6 +38,7 @@
#include "Application.h"
#include "BitmapFactory.h"
#include "Control.h"
#include "Clipping.h"
#include "FileDialog.h"
#include "MainWindow.h"
#include "Tree.h"
@ -49,6 +50,7 @@
#include "Selection.h"
#include "SoFCOffscreenRenderer.h"
#include "SoFCBoundingBox.h"
#include "SoFCUnifiedSelection.h"
#include "SoAxisCrossKit.h"
#include "View3DInventor.h"
#include "View3DInventorViewer.h"
@ -473,12 +475,15 @@ StdCmdToggleClipPlane::StdCmdToggleClipPlane()
Action * StdCmdToggleClipPlane::createAction(void)
{
Action *pcAction = (Action*)Command::createAction();
#if 0
pcAction->setCheckable(true);
#endif
return pcAction;
}
void StdCmdToggleClipPlane::activated(int iMsg)
{
#if 0
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
if (view) {
if (iMsg > 0 && !view->hasClippingPlane())
@ -486,10 +491,17 @@ void StdCmdToggleClipPlane::activated(int iMsg)
else if (iMsg == 0 && view->hasClippingPlane())
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)
{
#if 0
View3DInventor* view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
if (view) {
Action* action = qobject_cast<Action*>(_pcAction);
@ -503,6 +515,11 @@ bool StdCmdToggleClipPlane::isActive(void)
action->setChecked(false);
return false;
}
#else
if (Gui::Control().activeDialog())
return false;
return true;
#endif
}
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());
view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud);
SoNode* root = view->getSceneGraph();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(TRUE);
std::vector<SbVec2f> picked = view->getGLPolygon();
SoCamera* cam = view->getCamera();
SbViewVolume vv = cam->getViewVolume();
@ -1972,8 +1992,10 @@ void StdBoxSelection::activated(int iMsg)
if (view) {
View3DInventorViewer* viewer = view->getViewer();
if (!viewer->isSelecting()) {
viewer->startSelection(View3DInventorViewer::Rectangle);
viewer->startSelection(View3DInventorViewer::Rubberband);
viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback);
SoNode* root = viewer->getSceneGraph();
static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionRole.setValue(FALSE);
}
}
}

View File

@ -26,6 +26,7 @@
# include <cmath>
# include <float.h>
# include <climits>
# include <QCursor>
# include <QTimer>
#include <Inventor/nodes/SoCamera.h>
#endif
@ -53,6 +54,11 @@ DemoMode::DemoMode(QWidget* parent, Qt::WFlags fl)
timer->setInterval(1000 * ui->timeout->value());
connect(timer, SIGNAL(timeout()), this, SLOT(onAutoPlay()));
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 */
@ -82,6 +88,35 @@ void DemoMode::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
{
Document* doc = Application::Instance->activeDocument();
@ -186,6 +221,14 @@ void DemoMode::on_fullscreen_toggled(bool on)
view->setCurrentViewMode(on ? MDIView::/*TopLevel*/FullScreen : MDIView::Child);
this->activateWindow();
}
if (on) {
qApp->installEventFilter(this);
showHideTimer->start();
}
else {
qApp->removeEventFilter(this);
showHideTimer->stop();
}
}
void DemoMode::on_timeout_valueChanged(int v)

View File

@ -68,12 +68,19 @@ private:
Gui::View3DInventor* activeView() const;
void startAnimation(Gui::View3DInventor*);
void changeEvent(QEvent *e);
bool eventFilter(QObject *, QEvent *);
void showEvent(QShowEvent *);
void hideEvent(QHideEvent *);
private:
int oldvalue;
SbVec3f viewAxis;
bool wasHidden;
QPoint pnt;
QPoint oldPos;
Ui_DemoMode* ui;
QTimer* timer;
QTimer* showHideTimer;
};
} // namespace Dialog

View File

@ -1,15 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>Gui::Dialog::DlgAuthorization</class>
<widget class="QDialog" name="Gui::Dialog::DlgAuthorization">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>189</height>
<width>284</width>
<height>128</height>
</rect>
</property>
<property name="windowTitle">
@ -18,74 +16,16 @@
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>11</number>
</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" >
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="textLabel1">
<property name="text">
<string>&amp;OK</string>
</property>
<property name="shortcut" >
<string/>
</property>
<property name="autoDefault" >
<bool>true</bool>
</property>
<property name="default" >
<bool>true</bool>
<string>Username:</string>
</property>
</widget>
</item>
<item>
<spacer>
<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>&amp;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 row="1" column="1">
<widget class="QLineEdit" name="username"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="textLabel2">
@ -94,17 +34,14 @@
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLineEdit" name="username" />
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<string>User name:</string>
<item row="2" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="4" column="0" >
<item row="3" column="0" colspan="2">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -112,7 +49,7 @@
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0">
<size>
<width>21</width>
<height>41</height>
@ -120,48 +57,43 @@
</property>
</spacer>
</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>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>username</tabstop>
<tabstop>password</tabstop>
<tabstop>buttonOk</tabstop>
<tabstop>buttonCancel</tabstop>
</tabstops>
<resources/>
<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>
<connections/>
</ui>

View File

@ -40,9 +40,6 @@
<property name="spacing" >
<number>6</number>
</property>
<item rowspan="2" row="7" column="1" >
<widget class="QTextEdit" name="textEditComment" />
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabelName" >
<property name="text" >
@ -56,32 +53,16 @@
</property>
</widget>
</item>
<item row="8" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<item row="0" column="1" >
<widget class="QLineEdit" name="lineEditName" >
<property name="minimumSize" >
<size>
<width>91</width>
<height>240</height>
<width>0</width>
<height>25</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0" >
<widget class="QLabel" name="textLabelComment" >
<property name="text" >
<string>Commen&amp;t:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>textEditComment</cstring>
<property name="readOnly" >
<bool>true</bool>
</property>
</widget>
</item>
@ -108,40 +89,30 @@
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLineEdit" name="lineEditCreator" >
<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" >
<item row="2" column="0" >
<widget class="QLabel" name="textLabelUuid" >
<property name="text" >
<string>&amp;Last modified by:</string>
<string>UUID:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>lineEditLastMod</cstring>
</widget>
</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>
</widget>
</item>
<item row="2" column="0" >
<item row="3" column="0" >
<widget class="QLabel" name="textLabelCreator" >
<property name="text" >
<string>Created &amp;by:</string>
@ -154,20 +125,66 @@
</property>
</widget>
</item>
<item row="6" column="0" >
<widget class="QLabel" name="textLabelCompany" >
<item row="3" column="1" >
<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" >
<string>Com&amp;pany:</string>
<string>Creation &amp;date:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<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>
</widget>
</item>
<item row="5" column="0" >
<widget class="QLabel" name="textLabelLastMod" >
<property name="text" >
<string>&amp;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" >
<property name="text" >
<string>Last &amp;modification date:</string>
@ -181,29 +198,6 @@
</widget>
</item>
<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" >
<property name="minimumSize" >
<size>
@ -216,32 +210,61 @@
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="textLabelCreateDate" >
<item row="7" column="0" >
<widget class="QLabel" name="textLabelCompany" >
<property name="text" >
<string>Creation &amp;date:</string>
<string>Com&amp;pany:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>lineEditDate</cstring>
<cstring>lineEditCompany</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="lineEditName" >
<item row="7" column="1" >
<widget class="QLineEdit" name="lineEditCompany" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="readOnly" >
<bool>true</bool>
</widget>
</item>
<item row="8" column="0" >
<widget class="QLabel" name="textLabelComment" >
<property name="text" >
<string>Commen&amp;t:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy" >
<cstring>textEditComment</cstring>
</property>
</widget>
</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>
</widget>
</item>
@ -304,14 +327,6 @@
</widget>
<layoutdefault spacing="6" margin="11" />
<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>
<resources/>
<connections>

View File

@ -46,6 +46,7 @@ DlgProjectInformationImp::DlgProjectInformationImp( App::Document* doc, QWidget*
this->setupUi(this);
lineEditName->setText(QString::fromUtf8(doc->Label.getValue()));
lineEditPath->setText(QString::fromUtf8(doc->FileName.getValue()));
lineEditUuid->setText(QString::fromUtf8(doc->Uid.getValueStr().c_str()));
lineEditCreator->setText(QString::fromUtf8(doc->CreatedBy.getValue()));
lineEditDate->setText(QString::fromUtf8(doc->CreationDate.getValue()));
lineEditLastMod->setText(QString::fromUtf8(doc->LastModifiedBy.getValue()));

View File

@ -71,6 +71,7 @@ void DlgSettingsViewColor::saveSettings()
EditedVertexColor->onSave();
ConstructionColor->onSave();
FullyConstrainedColor->onSave();
BoundingBoxColor->onSave();
DefaultShapeColor->onSave();
DefaultShapeLineColor->onSave();
DefaultShapeLineWidth->onSave();
@ -94,6 +95,7 @@ void DlgSettingsViewColor::loadSettings()
EditedVertexColor->onRestore();
ConstructionColor->onRestore();
FullyConstrainedColor->onRestore();
BoundingBoxColor->onRestore();
DefaultShapeColor->onRestore();
DefaultShapeLineColor->onRestore();
DefaultShapeLineWidth->onRestore();

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>601</width>
<height>565</height>
<height>598</height>
</rect>
</property>
<property name="windowTitle">
@ -520,6 +520,33 @@
</property>
</widget>
</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>
</item>
<item row="0" column="0">
@ -660,6 +687,7 @@
<tabstop>EditedVertexColor</tabstop>
<tabstop>ConstructionColor</tabstop>
<tabstop>FullyConstrainedColor</tabstop>
<tabstop>BoundingBoxColor</tabstop>
<tabstop>radioButtonSimple</tabstop>
<tabstop>SelectionColor_Background</tabstop>
<tabstop>radioButtonGradient</tabstop>

View File

@ -288,7 +288,11 @@ void DlgCustomToolbars::on_moveActionRightButton_clicked()
QTreeWidgetItem* item = commandTreeWidget->currentItem();
if (item) {
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);
copy->setText(0, item->text(1));
copy->setIcon(0, item->icon(0));

View File

@ -571,43 +571,18 @@ bool Document::saveAs(void)
getMainWindow()->showMessage(QObject::tr("Save document under new filename..."));
QString exe = qApp->applicationName();
QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe),
FileDialog::getWorkingDirectory(), 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();
}
}
}
QString fn = FileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe),
QString(), QObject::tr("%1 document (*.FCStd)").arg(exe));
if (!fn.isEmpty()) {
QFileInfo fi;
fi.setFile(fn);
QString bn = fi.baseName();
const char * DocName = App::GetApplication().getDocumentName(getDocument());
// save as new file name
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());
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);
getMainWindow()->appendRecentFile(fi.filePath());
@ -695,9 +670,20 @@ void Document::RestoreDocFile(Base::Reader &reader)
for (i=0 ;i<Cnt ;i++) {
xmlReader.readElement("ViewProvider");
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());
if (pObj) // check if this feature has been registered
pObj->Restore(xmlReader);
if (expanded) {
Gui::ViewProviderDocumentObject* vp = static_cast<Gui::ViewProviderDocumentObject*>(pObj);
this->signalExpandObject(*vp, Gui::Expand);
}
xmlReader.readEndElement("ViewProvider");
}
xmlReader.readEndElement("ViewProviderData");
@ -784,7 +770,9 @@ void Document::SaveDocFile (Base::Writer &writer) const
const App::DocumentObject* doc = it->first;
ViewProvider* obj = it->second;
writer.Stream() << writer.ind() << "<ViewProvider name=\""
<< doc->getNameInDocument() << "\">" << std::endl;
<< doc->getNameInDocument() << "\" "
<< "expanded=\"" << (doc->testStatus(App::Expand) ? 1:0)
<< "\">" << std::endl;
obj->Save(writer);
writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
}

View File

@ -30,6 +30,8 @@
# include <boost/bind.hpp>
#endif
#include <boost/unordered_set.hpp>
#include "DocumentModel.h"
#include "Application.h"
#include "BitmapFactory.h"
@ -54,8 +56,6 @@ namespace Gui {
virtual ~DocumentModelIndex()
{ qDeleteAll(childItems); }
void reset()
{ qDeleteAll(childItems); childItems.clear(); }
void setParent(DocumentModelIndex* parent)
{ parentItem = parent; }
DocumentModelIndex *parent() const
@ -64,7 +64,12 @@ namespace Gui {
{ childItems.append(child); child->setParent(this); }
void removeChild(int row)
{ childItems.removeAt(row); }
QList<DocumentModelIndex*> removeAll()
{
QList<DocumentModelIndex*> list = childItems;
childItems.clear();
return list;
}
DocumentModelIndex *child(int row)
{ return childItems.value(row); }
int row() const
@ -91,11 +96,18 @@ namespace Gui {
return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
}
protected:
void reset()
{ qDeleteAll(childItems); childItems.clear(); }
protected:
DocumentModelIndex() : parentItem(0) {}
DocumentModelIndex *parentItem;
QList<DocumentModelIndex*> childItems;
};
// ------------------------------------------------------------------------
// Root node
class ApplicationIndex : public DocumentModelIndex
{
@ -104,9 +116,80 @@ namespace Gui {
public:
ApplicationIndex(){}
int findChild(const Gui::Document& d) const;
Qt::ItemFlags flags() const
{ return Qt::ItemIsEnabled; }
QVariant data(int role) const
Qt::ItemFlags flags() 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) {
return qApp->windowIcon();
@ -116,23 +199,58 @@ namespace Gui {
}
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)
documentIcon = new QIcon(Gui::BitmapFactory().pixmap("Document"));
vp_nodes[&vp->v].insert(vp);
}
int findViewProvider(const ViewProvider&) const;
void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
QVariant data(int role) const
void DocumentIndex::removeFromDocument(ViewProviderIndex* vp)
{
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) {
return *documentIcon;
@ -152,18 +270,43 @@ namespace Gui {
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:
const Gui::ViewProviderDocumentObject& v;
ViewProviderIndex(const Gui::ViewProviderDocumentObject& v) : v(v){}
void findViewProviders(const ViewProvider&, QList<ViewProviderIndex*>&) const;
QVariant data(int role) const
ViewProviderIndex::~ViewProviderIndex()
{
if (d) d->removeFromDocument(this);
}
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) {
return v.getIcon();
@ -184,57 +327,8 @@ namespace Gui {
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::ApplicationIndex,Gui::DocumentModelIndex);
@ -350,7 +444,7 @@ void DocumentModel::slotNewObject(const Gui::ViewProviderDocumentObject& obj)
QModelIndex parent = createIndex(index->row(),0,index);
int count_obj = index->childCount();
beginInsertRows(parent, count_obj, count_obj);
index->appendChild(new ViewProviderIndex(obj));
index->appendChild(new ViewProviderIndex(obj, index));
endInsertRows();
}
}
@ -399,35 +493,47 @@ void DocumentModel::slotChangeObject(const Gui::ViewProviderDocumentObject& obj,
else if (isPropertyLink(Prop)) {
App::Document* doc = fea->getDocument();
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);
if (row > -1) {
QList<DocumentModelIndex*> del_items;
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) {
int row = doc_index->findViewProvider(**vp);
int row = doc_index->rowOfViewProvider(**vp);
// is it a top-level child in the document
if (row >= 0) {
DocumentModelIndex* child = doc_index->child(row);
del_items.push_back(child);
QModelIndex parent = createIndex(doc_index->row(), 0, doc_index);
beginRemoveRows(parent, row, row);
doc_index->removeChild(row);
delete child;
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) {
QModelIndex parent = createIndex((*it)->row(),0,*it);
int count_obj = (*it)->childCount();
beginInsertRows(parent, count_obj, count_obj + (int)views.size());
for (std::vector<ViewProviderDocumentObject*>::iterator jt = views.begin(); jt != views.end(); ++jt)
(*it)->appendChild(new ViewProviderIndex(**jt));
endInsertRows();
beginRemoveRows(parent, 0, count_obj);
// remove all children but do not yet delete them
QList<DocumentModelIndex*> items = (*it)->removeAll();
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()))
return true;
if (prop.isDerivedFrom(App::PropertyLinkSub::getClassTypeId()))
return true;
if (prop.isDerivedFrom(App::PropertyLinkList::getClassTypeId()))
return true;
if (prop.isDerivedFrom(App::PropertyLinkSubList::getClassTypeId()))
return true;
return false;
}
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;
if (prop.isDerivedFrom(App::PropertyLink::getClassTypeId())) {
App::DocumentObject* obj;
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) {
std::vector<ViewProviderDocumentObject*> views;
std::vector<App::DocumentObject*> childs = obj.claimChildren();
for (std::vector<App::DocumentObject*>::iterator it = childs.begin(); it != childs.end(); ++it) {
ViewProvider* view = doc.getViewProvider(*it);
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

View File

@ -67,8 +67,8 @@ private:
const Document* getDocument(const QModelIndex&) const;
bool isPropertyLink(const App::Property&) const;
std::vector<ViewProviderDocumentObject*> getLinkedObjects
(const Gui::Document&, const App::Property&) const;
std::vector<ViewProviderDocumentObject*> claimChildren
(const Document&, const ViewProviderDocumentObject&) const;
private:
struct DocumentModelP *d;

View File

@ -27,7 +27,9 @@
# include <QHBoxLayout>
#endif
#include <QAuthenticator>
#include "DownloadDialog.h"
#include "ui_DlgAuthorization.h"
using namespace Gui::Dialog;
@ -202,6 +204,16 @@ void DownloadDialog::updateDataReadProgress(int bytesRead, int totalBytes)
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
View 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
View 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
View 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
View 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
View 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

View 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>

View File

@ -26,11 +26,14 @@
# include <QApplication>
# include <QButtonGroup>
# include <QComboBox>
# include <QDesktopServices>
# include <QGridLayout>
# include <QGroupBox>
# include <QLineEdit>
# include <QPushButton>
# include <QRadioButton>
# include <QStyle>
# include <QUrl>
#endif
#include <Base/Parameter.h>
@ -45,6 +48,32 @@ using namespace Gui;
/* 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.
*/
@ -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
// existing file. Hence we must extract the first matching suffix from the filter list and append it
// 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);
#endif
if (!file.isEmpty()) {
setWorkingDirectory(file);
return file;
@ -129,7 +188,36 @@ QString FileDialog::getOpenFileName(QWidget * parent, const QString & caption, c
#if defined(FC_OS_MACOSX)
options |= QFileDialog::DontUseNativeDialog;
#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);
#endif
if (!file.isEmpty()) {
setWorkingDirectory(file);
return file;
@ -155,7 +243,36 @@ QStringList FileDialog::getOpenFileNames (QWidget * parent, const QString & capt
#if defined(FC_OS_MACOSX)
options |= QFileDialog::DontUseNativeDialog;
#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);
#endif
if (!files.isEmpty()) {
setWorkingDirectory(files.front());
}

View File

@ -56,6 +56,14 @@ public:
static QString getWorkingDirectory();
static void setWorkingDirectory( const QString& );
FileDialog(QWidget * parent = 0);
~FileDialog();
void accept();
private Q_SLOTS:
void onSelectedFilter(const QString&);
};
// ----------------------------------------------------------------------

View File

@ -25,10 +25,10 @@
#ifndef _PreComp_
# include <QMenu>
# include <QMouseEvent>
# include <Inventor/nodes/SoCamera.h>
#endif
#include <Inventor/SbVec2s.h>
#include "View3DInventorViewer.h"
#include "GLPainter.h"
#include "Flag.h"
@ -455,4 +455,76 @@ QSize FlagLayout::calculateSize(SizeType sizeType) const
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"

View File

@ -29,9 +29,11 @@
#include <QWidgetItem>
#include <QGLWidget>
#include <Inventor/SbVec3f.h>
#include <Gui/GLPainter.h>
namespace Gui {
class View3DInventorViewer;
/**
* @author Werner Mayer
*/
@ -98,6 +100,8 @@ private:
class FlagLayout : public QLayout
{
Q_OBJECT
public:
enum Position { TopLeft, TopRight, BottomLeft, BottomRight };
@ -136,6 +140,24 @@ private:
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

View File

@ -31,6 +31,8 @@
using namespace Gui;
TYPESYSTEM_SOURCE_ABSTRACT(Gui::GLGraphicsItem, Base::BaseClass);
GLPainter::GLPainter() : viewer(0), logicOp(false), lineStipple(false)
{
}

View File

@ -33,6 +33,8 @@
#include <GL/gl.h>
#endif
#include <Base/BaseClass.h>
namespace Gui {
class View3DInventorViewer;
class GuiExport GLPainter
@ -71,6 +73,20 @@ private:
bool lineStipple;
};
class GuiExport GLGraphicsItem : public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
GLGraphicsItem()
{
}
virtual ~GLGraphicsItem()
{
}
virtual void paintGL() = 0;
};
} // namespace Gui
#endif // GUI_GLPAINTER_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

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