Compare commits

..

233 Commits

Author SHA1 Message Date
Uwe f5d13554ec [FEM] [skip CI] remove unused import for potential 2022-08-10 13:44:09 +02:00
Uwe 57e0e6e769 [FEM] [skip CI] formatting fix for potential 2022-08-10 13:42:54 +02:00
Uwe 31376b12ad [FEM] electric Potential: add missing conversion
- add missing conversion of property change that was already done before FC 0.20
2022-08-10 13:33:39 +02:00
Uwe c96fe6b32e [FEM] Elmer: fix material bug and improve material handling
- for fluid material writing the elasticity solver failed with unknown Young Modulus
- fix regression with checking for fluid material. Checking the material of the bodies is not sufficient. One can e.g. have a solid without bodies defined, then it applied to all bodies and there might be a fluid defined for only one body. Checking the body's material would then deliver there is no fluid
2022-08-10 06:17:04 +02:00
Uwe c06f24122b [FEM] update a bimetal testfile 2022-08-10 04:26:37 +02:00
Uwe 88dc25d151 [FEM] Elmer: set constraints for relaxation factor
- the relaxation factor is crucial for nonlinear systems thus help the user by setting constraints and convenient steps.
Since the property stays a float no update is necessary, existing properties just stay a normal float
2022-08-10 04:11:07 +02:00
Uwe ad7e780a1f [FEM] Elmer: notify users about missing fluid material
- it was often unclear when no flow equation was written to the case.sif (was a regression FC0.20)
2022-08-10 03:29:51 +02:00
Uwe 4d5135ac4b [FEM] fix bimetall example
- add missing density
- set a second temperature to make the heat solver actually working
- adapt to new defaults
2022-08-10 02:28:13 +02:00
Uwe a00268b5ed [Material] add materials used by our examples
- add generic copper and invar
- also extend the generic aluminum card
2022-08-10 02:09:35 +02:00
Uwe c31af916bc [FEM] Elmer: automatic update for BiCGstablDegree
- up to last week we used the invalid BiCGstablDegree 0 thus update to the default of 2
2022-08-10 02:08:54 +02:00
Uwe 25b39419fd [FEM] fix selection issues with flow velocity constraint
- same fix as commit 7e071623 for flow velocity constraint
- the used selection widget did not highlight the selected faces. This made it very hard to work with when one has an existing document where e.g. 5 faces have a certain velocity and you cannot figure out which ones.
To fix this use another selection widget
2022-08-10 01:38:55 +02:00
Uwe 18bdc5c551 [Part] manually backport second part of today's override fixes 2022-08-10 01:30:59 +02:00
wmayer 3c8404fd09 Part: fix build failures with OCC >= 7.6 2022-08-10 00:59:45 +02:00
Uwe 7f8c5bcd85 [FEM] Elmer: fix broken example
- (a regression to FC 0.20.0), use new settings ("direct" is already the default, iterative solving takes here about 5 times longer, DisplaceMesh must be False)
2022-08-09 05:39:11 +02:00
Uwe b2fe784efd [Win installer] prepare for 0.20.1 release 2022-08-09 04:21:57 +02:00
Uwe ddbcc0b3d5 [Build] output point release version
- to Splashscreen, About, MainWindow and Console
2022-08-09 03:32:24 +02:00
Uwe 87953bf330 [FEM] increase size of generic solver task panel
- increase it to size of CCX panel to create more room for the log output
2022-08-09 03:23:52 +02:00
sliptonic 9e267241fe Merge pull request #7333 from mlampert/bugfix/external-thread-issues
PATH: Bugfix/external thread issues
2022-08-09 00:49:40 +02:00
Uwe 8fe6438ca8 [FEM] backport a variable renaming
- to avoid merge conflicts
2022-08-08 12:49:46 +02:00
Uwe 855634a670 [FEM] Elmer: scale EigenMode results
- for an not yet known reason the result from Elmer are only for eigen analyses a factor 1000 (we send the mesh scaled to Elmer and it seems the eigen solver does not notice this)
Therefore scale these results
2022-08-08 12:36:17 +02:00
Uwe 194902fb90 [FEM] fix warp filter factor
- since our mesh is in mm, we must multiply the set factor by 1000 to get the real factor. This applies also for pipelines from CCX results.
Now the factor fits with the factor one can set in the CCX results dialog
2022-08-08 12:35:21 +02:00
wmayer b221137067 Gui: set width of list box according to text length 2022-08-08 12:34:18 +02:00
Uwe 2be012c9c6 [FEM] backport some changes to resolve merge conflicts
- manually done
2022-08-08 11:39:13 +02:00
berniev 3e6f7cfc53 Gui: redundant void 2 2022-08-08 11:16:32 +02:00
berniev 8714208cfb App: redundant void 2 2022-08-08 11:14:47 +02:00
wmayer 0ddacad17a Mod: [skip ci] improve whitespace 2022-08-08 10:59:29 +02:00
wmayer 73af68afc5 Gui: [skip ci] include header with export macros 2022-08-08 10:58:22 +02:00
Uwe 365230d313 [FEM] update test files 2022-08-08 03:26:56 +02:00
Uwe 898a57ca29 [FEM] collected Elmer fixes
- manually merge the recent Elmer fixes and novelties
2022-08-08 02:39:14 +02:00
Uwe c2ae76dd77 [FEM] add generic Aluminum material
- with full thermal info
2022-08-08 02:24:09 +02:00
Roy-043 02d6b1dd51 Sketcher: Fix sWhatsThis for Sketcher_CompConstrainRadDia (#7324) 2022-08-08 02:14:04 +02:00
luz paz bcdc681755 FEM: remove trailing whitespace from various FEM files 2022-08-08 02:13:22 +02:00
Uwe d8ed961e35 [FEM] fix pipeline recompute issue
- after a simulation was run, the pipelines and its childs are recomputed but its shape coloring is not updated.

- also update XML documentation
- also remove comment in tasks.py for now
2022-08-08 02:08:05 +02:00
Uwe 73132b3743 [FEM] add framework to scale result mesh values
- it seems that we will need to scale result values (probably for the Elmer Eigen solver)
  This PR adds the framework to do this. It is meant for Elmer but designed versatile.
2022-08-08 02:06:32 +02:00
Uwe 6da987a91b [FEM] fix pipeline recompute bug
- on recomputing scalar or warp filters the information about the field was lost.
  This is because the validity of an array was tested before it is actually filled

- also fix MSVC warning of using a C++ keyword as variable
- also avoid an unnecessary recompute after Elmer solver was run
2022-08-08 00:09:37 +02:00
wmayer 7fd0a19ed7 Gui: improve integrated Python console:
* correctly handle the case that Py_BuildValue() can return a null pointer
* fix a latin1 <-> UTF-8 conversion problem
2022-08-07 19:36:08 +02:00
Uwe 5922dd75bf [FEM] pipeline fix when there is no field
- for the case that pipeline with a field is active, then another pipeline that does not display any field, we cannot just return because the pipeline cannot have the color bar range of the prevision pipeline
2022-08-07 15:27:29 +02:00
Uwe f99c270091 [FEM] [skip CI] set unit for potential loads 2022-08-07 15:18:47 +02:00
Uwe 7fcf092632 [FEM] update Elmer test files 2022-08-07 06:54:37 +02:00
Uwe 93db713b0e [Base] attempt to make a Path backport compiling 2022-08-07 06:49:58 +02:00
Uwe 1571a4817f [FEM] make point filter aware of electric flux
- make point filter aware of electric flux (manually backported)
2022-08-07 06:35:31 +02:00
Uwe 9fd20de4b8 [FEM] fix selection issues with electrostatic constraint
- the used selection widget did not highlight the selected faces. This made it very hard to work with when one has an existing document where e.g. 5 faces have a certain voltage and you cannot figure out which ones.
To fix this use another selection widget
2022-08-07 06:30:53 +02:00
Uwe a4d95722e2 [Fem] Elmer: writer: remove unused variable 2022-08-07 06:29:48 +02:00
Uwe 59da0af311 [FEM] make point filter aware of force density 2022-08-07 06:28:01 +02:00
Uwe 7fbae8a314 [FEM] Elmer: resale the mesh using Elmer
- according to Peter from the Elmer team, we can use Elmer for both, scaling in and scaling back just for consistency
2022-08-07 06:25:28 +02:00
Uwe 8913921f5b [FEM] Elmer: fix pipeline update issue
- the existing result pipeline can have several children. They must all be updated.
2022-08-07 06:24:16 +02:00
berniev da88c7a6d3 give success message normal prominence 2022-08-07 06:23:23 +02:00
sliptonic 002fcacd57 Merge pull request #7278 from mlampert/bugfix/vcarve-c++-exception
PATH: Bugfix/vcarve c++ exception
2022-08-06 03:58:33 +02:00
Uwe 0c14bcb0d9 [Fem] Elmer: update test files 2022-08-05 02:42:45 +02:00
Yorik van Havre bfe8b89da1 Draft: Enabled shortcut for undo segment - fixes #6181
That shortcut had apparently been left out last time the system was recoded..
I used the default shortcut '/' because Ctrl doesn't really work with the
current system, and Z is already taken
2022-08-05 02:30:03 +02:00
Uwe eb4a62f945 [FEM] Elmer: sync input scaling with master 2022-08-05 02:29:14 +02:00
Uwe 40c4f6585b [FEM] fix enable editing for all solvers
- currently for Z88 nothing happens when clicking the Edit button in the solver task dialog. The reason is that opening *.txt files was never implemented
- also do this for Elmer
- for Z88 we need to open several file for a proper editing because the solver info is distributed over these files
2022-08-04 04:25:36 +02:00
Uwe 75d970afda [FEM] Elmer: setup new pipelines like we do for CCX
and manually new created ones
2022-08-04 04:25:00 +02:00
Uwe 655508d68e [FEM] Elmer: use different default linear solver
- BiCGStabl is as robust as BiCGStab but in all tested cases it converges faster
2022-08-04 04:24:34 +02:00
Uwe c66e4b4772 [FEM] Elmer: use direct solving as default for stresses
- direct solving is sometimes even 10 times faster (as fast as CCX) and as accurate as CCX
2022-08-04 04:22:59 +02:00
Uwe 2e3d9dadda [FEM] pipeline: minor highlighting fix
- if a pipeline is invisible the highlighting must not be triggered
2022-08-04 04:21:59 +02:00
Günter Neiß bfe4c724b4 OpenSCAD: remove SCAD-Import error in importCSG.py
Signed-off-by: Günter Neiß <gneiss@web.de>
2022-08-04 01:20:45 +02:00
wmayer ff659b1352 Fem: [skip ci] fix possible crash in PropertyPostDataObject::getMemSize 2022-08-04 00:50:50 +02:00
Uwe b06edfcb97 [Gui] QSint: missing piece to fix QGroupBox visibility
- also the freecadscheme must be adapted (e.g. for PartDesign dialogs)
- fixes now #6102 completely
2022-08-04 00:49:51 +02:00
Chris Hennes d1d9a17a98 Addon Manager: fix thread termination bug 2022-08-03 01:21:45 +02:00
wmayer 67c24b5749 Fem: [skip ci] replace the SoAnnotation with an SoSeparator to fix rendering artifacts for non-convex objects 2022-08-03 01:15:58 +02:00
wmayer 426ff82c87 Fem: use SoAnnotation to highlight result pipeline objects 2022-08-03 01:15:14 +02:00
carlopav 22e8085394 [Draft] Fix Draft Edit AddPoint with BSpline
ref. https://forum.freecadweb.org/viewtopic.php?p=613622#p613622

Fix Bug when adding point to a BSpline.
2022-08-03 01:14:01 +02:00
luz paz b522212d71 AddonManager: Fix source comment typos
[skip ci]
2022-08-03 01:11:58 +02:00
Uwe 6146311a94 - fixes #6102
- the point is that we don't set any style for the group boxes, therefore the Windows style is applied as nothing was set yet. The default Windows style is the color #dddddd which is hardly visible on our blue default style.
as solution set an explicit color.
2022-08-02 05:22:30 +02:00
Yorik van Havre 68b5d8dbca Merge pull request #7259 from Roy-043/Draft-Fix-handling-of-groups-on-move-copy-and-rotate-copy
Draft: Fix handling of groups on move-copy and rotate-copy
2022-08-02 05:19:10 +02:00
wmayer 3a424136ff Spreadsheet: fixes #7285: [Bug] FreeCAD crashes if cell value ' is set in Spreadsheet 2022-08-01 11:51:53 +02:00
Uwe 67682e2bb3 [.github] [skip CI] checks.yml: disable a whitespace check
- todo whitespace is not important
2022-08-01 04:38:47 +02:00
Floriansimmer 65b1048463 Ci v2 (#7282)
* Github: Build and Test

Build and Test:
- ccache
- build
- Unittest
- install
- Unittest of install
- report

misc:
- use .clang-tidy file to configure Clang-tidy checks
- use use .pylintrc to configure Pylint checks
- Update changed-files Action
- better regex for file extension filter
- show enabled clang-tidy checks in Step Report
- show enabled Pylint Checks
- cpplint filter documentation
- modified cpplint filters recomended by https://github.com/sider/runners/blob/HEAD/images/cpplint/sider_recommended_CPPLINT.cfg
- fixed Branch filter for Clazy QT6 checks --> has only worked on pull requests
- fail the CI only on Build  errors, Unittest errors and misspellings

* Github: remove Codespell action as it is now integrated into the check workflow
2022-08-01 04:37:23 +02:00
Uwe 6975093d6e [FEM] Elmer: fixes for the point filter
- use correct names and support all possible outputs
2022-08-01 04:35:32 +02:00
Uwe 2893474ab2 [FEM] Elmer: update .sif files
- because of solver default settings change
2022-08-01 04:34:41 +02:00
Uwe 4430a1cce9 [FEM] Elmer: set sensible defaults for elasticity equation
- for BiCGstabl the minimal degree is 2, but 3 is recommended
- when adding the equation, it should do something, therefore enable the calculation of the principal stresses (as it was, nothing was calculated except of the displacement)
2022-08-01 04:34:41 +02:00
wmayer 75b912b173 Fem: implement a selection observer to notify a ViewProviderFemPostObject when its selection status has changed 2022-07-31 21:20:09 +02:00
Uwe 01ae4db181 [FEM] Constraint: BodeHeat: fix regression from commit 22c64ef8
- a simple indentation mistake
2022-07-31 21:19:00 +02:00
Uwe 8303a55092 [FEM] add missing eigenfrequcy calculation for Elmer
- while for CCX we output the eigenfrequency, for Elmer the user had to perform the calculation of a sqrt of the complex result.
This is inconvenient and error-prone and also requires the knowledge where the result is output by Elmer and in what format. (cast me more than an hour to find this out)
Therefore perform the calculation for the user and output the result.
2022-07-31 05:44:14 +02:00
Uwe 9c7f869e3b [FEM] Elmer: fix small number property handling
- use an expression as discussed: https://forum.freecadweb.org/viewtopic.php?p=613897#p613897
2022-07-31 05:43:01 +02:00
Uwe fdb3dd9de4 [FEM] Elmer: fix eigenmode results for point filter
Elmers' eigenmode results have a different result name
2022-07-31 05:42:06 +02:00
adrianinsaval 014ed4ccc5 Bump PACKAGE_VERSION_PATCH for next patch release 2022-07-31 05:39:28 +02:00
Chris Hennes e51acb490c Addon Manager: Add other_files download for wiki macros 2022-07-30 21:35:19 -05:00
Uwe 58c9ed6028 [FEM] Elmer: add missing direct variant MUMPS
- also use capitalized wording to Umfpack as Elmer does
2022-07-30 20:10:35 +02:00
Zheng, Lei bb55fe76db Gui: fix ViewProviderLink transform with scale
Fixes FreeCAD/FreeCAD#7113
2022-07-30 19:17:55 +02:00
Uwe 451d95d04a Revert "App: fixes #7277: Write to network drive fails on Windows"
This reverts commit c00740aa15.
2022-07-30 16:09:50 +02:00
wmayer c00740aa15 App: fixes #7277: Write to network drive fails on Windows 2022-07-30 14:04:33 +02:00
Adrian Insaurralde Avalos 25ea7e41a6 [python init] Prepend install prefix if libdir is not absolute
For python init script so it can work by default
2022-07-30 00:33:07 +02:00
wmayer 191c95c0ea Mod: [skip ci] fix warning: [-Wreturn-std-move] 2022-07-30 00:21:35 +02:00
wmayer f5096a17e2 Gui: [skip ci] mkae sure the tooltip in ActionGroup::onActivated() disappears again 2022-07-30 00:12:29 +02:00
wmayer 130da19292 App: fixes #7112: Addon manager does not work on windows with special characters in the username 2022-07-29 10:06:34 -05:00
Wanderer Fan 5df4501ccc [TD]fix redraw does not paint all views 2022-07-29 01:37:00 +02:00
Wanderer Fan 919e31ea27 [TD]fix Symbol update on property change 2022-07-29 01:35:59 +02:00
Uwe 60499ffcd4 [Sketcher] fix icon name
- fix a FIXME, Sketcher_CreateEllipse depicts already the right thing, it just has to be renamed
2022-07-29 01:34:51 +02:00
Chris Hennes 8811dc4a48 Addon Manager: Fix get_zip_url for non-github URLs 2022-07-28 02:11:24 +02:00
wmayer 86686ab7ed Part: [skip ci] add unit test for PR #7260 2022-07-27 17:02:48 +02:00
Uwe 55bcd7bf19 [FEM] fix PostObject hiding issue
- when a PostObject is hidden the FemPostDataAtPointFilter must not be taken into account
2022-07-27 16:59:14 +02:00
Uwe 264227ae7b [FEM] sync an icon with master 2022-07-27 16:45:05 +02:00
Uwe 67cafa1453 [FEM] PostDataAtPoint: remove unnecessary style setting
- PostDataAtPoint is a point therefore setting a filling style is not necessary

- also fix a typo in a comment
2022-07-27 16:16:18 +02:00
Uwe a181437a71 [FEM] skip CI] update a comment 2022-07-27 16:11:23 +02:00
Uwe 390461c581 [FEM] update ViewProvider selection code
as suggested in
https://github.com/FreeCAD/FreeCAD/commit/67e836b7e953cf5901a337a6f56df34a0446cd6a#r79459854
2022-07-27 16:11:23 +02:00
Uwe c1b350f117 [Sketcher] CommandCreateGeo: next attempt to fix compilation 2022-07-27 16:03:37 +02:00
Uwe d5404eed47 [Sketcher] CommandCreateGeo: fix compilation 2022-07-27 15:40:06 +02:00
tomate44 75186322eb [Part] BSplineSurface: fix KnotSequence for periodic BSpline surfaces 2022-07-27 15:03:31 +02:00
Uwe 93fe24201a [Sketcher] [skip CI] whitespace fix 2022-07-27 15:02:50 +02:00
0penBrain 9d729cf114 [BUGFIX] Sketcher: fix icon normal/construction toggling when commands used in custom toolbar
Fixes #7064
2022-07-27 14:51:12 +02:00
Chrismettal 0d10011b38 [Stylesheets] Remove whitespace and add "checked" icon style 2022-07-27 14:24:07 +02:00
Uwe f81f9e3bab [FEM] BodyHeat constraint: use unique icon
- it was not possible to distinguish the constraint from the heatFlux constraint
2022-07-27 14:04:40 +02:00
Uwe 4b092abdb0 [FEM] BodyHeat constraint: hide unused property
- the constraint does not take a references and when trying to set one as user because one thinks this empty property must be set, one gets a recompute error
2022-07-27 14:04:40 +02:00
wmayer 341e017960 Spreadsheet: fix several memory leaks 2022-07-27 14:02:45 +02:00
Uwe aae0a70bb6 [FEM] PostObject: improve color bar refreshing
- for data point filters the color bar must not be updated
2022-07-26 04:14:58 +02:00
Uwe ff1e67b44d [FEM] Elmer writer: fix errors on missing material properties
- we must in this case raise an error and stop the writer script
2022-07-26 04:13:55 +02:00
Uwe a3e00bd73e [FEM] update bodyHeatSource
- to the state of the other constraints

(this constraint is currently completely broken by the way)
2022-07-26 04:13:17 +02:00
adrianinsaval 28773a081c Improve grid maxNumberOfLines warning message 2022-07-25 21:03:31 +02:00
wmayer 632ac1521a Part: add instruction how to adjust the maximum number of grid lines 2022-07-25 21:01:28 +02:00
Uwe 53977e0220 Fem: [skip ci] Fix several clazy issues: * Maybe you meant to call base method instead [-Wclazy-skipped-base-method] * Using copy-ctor but class SbMatrix has a trivial copy-ctor but non trivial assign operator [-Wclazy-rule-of-two-soft] * Missing emit keyword on signal call FemGui::PointMarker::PointsChanged [-Wclazy-incorrect-emit] 2022-07-25 20:47:42 +02:00
Uwe 6ba6463107 [FEM] Elmer: fix python error when solver failed
we must then stop the execution of the script
2022-07-25 03:39:41 +02:00
Uwe 9cfbdbe96c [FEM] ViewProviderDocumentObject: fix parenthesis mistake
(I don't know how this happened)
2022-07-24 19:34:55 +02:00
Uwe 7a9a7544ea [FEM] fix color bar handling on hiding post objects
- fixed the remaining part of #7230: on hiding an object, refresh the color bar of the new visible object (if there is any)
2022-07-24 19:34:55 +02:00
Uwe a1d57f9877 [FEM] set default selection mode to BoundBox for post objects
- this fixes a long-standing annoyance that popped up also from time to time in the forum:
  the post objects deliver information via its coloring but a selection in the tree changed the shape color

Even experienced users like me did not know about the SelectionStyle property and always had to click into the model to see the real color, not the selection color.
Therefore SelectionStyle set to BoundBox is sensible as default settings for post objects since this assures that the users always see the right coloring.
2022-07-24 19:34:55 +02:00
Uwe 5bea268817 [.github] try to get the checks also for the 0-20 branch 2022-07-24 06:10:09 +02:00
Uwe add9dd377b Revert "a test for .github"
This reverts commit 25865955b1.
2022-07-24 06:09:11 +02:00
Uwe 6fd477d34b [.github] disable tidy checks for now
- as requested in https://github.com/FreeCAD/FreeCAD/pull/7152#issuecomment-1193176866
2022-07-24 06:07:39 +02:00
Uwe 3b6a83e1b4 [.github] disable clang checks for now
see https://github.com/FreeCAD/FreeCAD/pull/7152#issuecomment-1193167296
2022-07-24 06:07:39 +02:00
Floriansimmer 777bafbc1c Github: basic check CI Run (#7152)
* Github: basic check CI Run

- trailing Whitespace
- tab
- string based QT connections
- Cpplint
- pylint
- Black
- clang-format
- Codespell
- clang-tidy
- clazy (+QT6 Checks)
- Report
2022-07-24 06:07:39 +02:00
mosfet80 03ad5fd551 Git ignore hidden files with defined exceptions (#7108)
* git ignore all hidden files

* Removal file with non-existent link

* git Ignore all hidden files except .gitignore

* Set exceptions in gitignore
2022-07-24 06:07:39 +02:00
Uwe 25865955b1 a test for .github
ignore
2022-07-24 06:03:54 +02:00
Uwe a5860ad542 [FEM] fix regression of missing stress results
- fixes the regression that went in short as "last minute fix": commit 3af54a7dda -> fixes #7242

- also remove a doubled entry in an IF
2022-07-24 05:51:23 +02:00
Uwe ca013f6af7 [FEM] TaskBoxes: add missing info about transparency
The user had no info about the current transparency nor the value he will be selecting.
2022-07-24 05:50:28 +02:00
Uwe 85c8aeb40c [FEM] task_material_common: add a comment 2022-07-23 17:39:36 +02:00
Uwe 8c376a89f2 [FEM] fix material task dialog for fluids
- this fixes a mistake from commit ef088674
- it also consistently use the thermal expansion coefficient
- add code comments

now the material task dialog works with all fluid materials without errors or warnings
2022-07-23 17:39:36 +02:00
Syres916 39fd2593c1 [Part] Bugfix Primitives correction of decimal..
...places on creation
See https://forum.freecadweb.org/viewtopic.php?f=3&t=70339
2022-07-23 17:37:04 +02:00
wmayer fdeee21237 Part: fix TopoShape.isInside() for faces 2022-07-23 17:35:43 +02:00
Uwe 58a87e1ca4 [FEM] better fix for missing colorbar update for FemPostObject
- better fix for #7230 because we can call the direct paint method and because the bar is now also updated when the object is shown

- also add a ToDo note
2022-07-23 17:16:49 +02:00
Uwe 34e60c6731 [FEM] fix missing colorbar update for FemPostObject
- fixes issue #7230

- to update the color bar for post objects, the Field property has to be reset to trigger this. This PR does this.
2022-07-23 17:16:49 +02:00
Roy-043 fc33aed8c1 Arch: Housekeeping: import translate from correct file 2022-07-23 17:00:33 +02:00
Uwe 8ad3fc8ccc [FEM] [skip CI] fix UI file height entry
- was automatically done by QT designer
2022-07-23 16:59:55 +02:00
Uwe a64469320c [FEM] [skipCI] ViewProviderFemPostPipeline: remove unused include
- also sorting
2022-07-23 16:58:39 +02:00
Yorik van Havre 96ea0d266a Merge pull request #7215 from Roy-043/Draft-Remove-unnecessary-DisplayStatusbar-preference
Draft: Remove unnecessary DisplayStatusbar preference
2022-07-20 12:19:08 +02:00
Uwe 832100482c [PD] TaskExtrudeParameters: add missing simplification
forgot this change in commit 98dae1b2
2022-07-20 12:18:07 +02:00
Uwe f9f753e321 [PD] TaskExtrudeParameters: simplify code
to avoid several time the same translatable string
2022-07-20 03:22:44 +02:00
adrianinsaval fb223c2587 [PD Pad/Pocket] Fix bug with midplane usage in TwoLengths mode (#7216)
* [PD Pad/Pocket] Fix bug with midplane usage in TwoLengths mode
2022-07-20 03:22:03 +02:00
wmayer c98a03ecc6 Gui: fix crash in ViewProviderLink::currentDraggingPlacement() if there is no active dragger 2022-07-20 03:21:35 +02:00
wmayer 7f39542a73 Part: add instruction how to adjust the maximum number of grid lines 2022-07-20 03:21:01 +02:00
Yorik van Havre cc3d165ed8 Merge pull request #7181 from manuvarkey/bug_fix_1
Fix bug #6679, add new profiles
2022-07-19 03:16:29 +02:00
Roy-043 58d27e220f Arch: Fix getCutVolume in ArchCommands.py 2022-07-19 03:13:34 +02:00
Yorik van Havre 3b5dd5b852 Merge pull request #7200 from Roy-043/Draft-Fix-color-handling-in-make_point.py
Draft: Fix color handling in make_point.py
2022-07-19 03:12:37 +02:00
Yorik van Havre d385cbece7 Merge pull request #7174 from Roy-043/Draft-Fix-EditMode-for-hatch,-facebinder-and-shapestring
Draft: Fix EditMode for hatch, facebinder and shapestring
2022-07-19 03:11:24 +02:00
Yorik van Havre 98897fb356 Merge pull request #7176 from Roy-043/Draft_Add_resetEdit_to_gui_hatch.py
Draft: Add resetEdit to gui_hatch.py
2022-07-19 03:07:46 +02:00
Yorik van Havre 8b433990ad Merge pull request #7173 from Roy-043/Draft_Fix_setEdit_in_view_text.py
Draft: Fix setEdit in view_text.py
2022-07-19 03:06:52 +02:00
Yorik van Havre 0e7449aef1 Merge pull request #7141 from Roy-043/Draft-make_hatch.py-should-return-the-object
Draft: make_hatch.py should return the object
2022-07-19 03:04:37 +02:00
sliptonic feab004970 Merge pull request #6974 from agren/restore-path-drilling-retract-behaviour
Path: Restore drilling op retract value to user supplied Retract Height
2022-07-18 00:38:38 +02:00
Uwe 136eb1d17a [PD] add parameter enabling logic for pad/pocket
- currently all parameters are always enabled and thus can lead to errors like the one reported here:
https://forum.freecadweb.org/viewtopic.php?f=3&t=70266
2022-07-18 00:31:55 +02:00
Uwe 50f112eaff [PD] improve face selection for Pad/Pocket
- this PR extends PR #7191 as described in this forum thread: https://forum.freecadweb.org/viewtopic.php?f=3&t=70327
2022-07-18 00:29:09 +02:00
Uwe a7dbbd5f21 [FEM] fix Z88 binary handling
- when the binary was not found, the function called the non-existing binary
- also push error message for Elmer and Z88 to the status info so that user gets feedback also when report view console is not shown
- uniform wording to 'binary'
- avoid unnecessary console output
2022-07-17 03:39:21 +02:00
Uwe 89ecdae088 [PD] fix Pad/Pocket logic issue
- fixes the bug reported in https://forum.freecadweb.org/viewtopic.php?f=3&t=70266
  as Method #2
  -> When switching to two dimensions, symmetric must be unchecked if it is checked
2022-07-17 03:24:19 +02:00
Uwe 13c4de32f2 [FEM] check if solver executables exist
- currently one can enter any path for the solver executables, a check is missing

- moreover for Z88 the executable name is error-prone (just happened to me and cost me half an hour to find out what is wrong), therefore check also the correct filename. For Elmer this cannot be done since there are different executables one can choose of (e.g. for multi-threading etc.)
2022-07-17 03:21:42 +02:00
Uwe abc61d3e14 [FEM] check if Gmsh, CCX and Mystran solver binaries exist
- adds the check like we have already for Z88 and Elmer
- also remove an unnecessary return statement
2022-07-17 03:13:59 +02:00
Uwe 6be3aef0e2 [FEM] fix CCX (new framework) binary handling
- when the binary was not found, the function called the non-existing binary
- also push error message to the status info so that user gets feedback also when report view console is not shown
2022-07-17 03:07:50 +02:00
Uwe 8cd18ce93e [FEM] [skip CI] tell user when Elmer write succeeded
At the moment the user gets no feedback, while for Z88 and CCX he gets a result
2022-07-17 03:04:12 +02:00
Uwe 7979e8c639 [Gui] preferences: clarify Part/PD page
- users are confused that we have a preferences page named "Part design" that also defines things for the Part WB. The Wiki is clear that the preferences page is for both, Part and PD, however the UI is not.
This PR makes this clear.
2022-07-16 18:09:15 +02:00
wmayer e0a8a7f306 PD: fix ProfileBased::getSupportFace() to also handle the case where a support face is selected 2022-07-16 17:35:34 +02:00
wmayer 233685616d PD: rename getUpToFaceFromLinkSub to getFaceFromLinkSub 2022-07-16 17:35:34 +02:00
Roy-043 22c971499a Update view_facebinder.py
There is no need for `Gui.Control.closeDialog()` in `setEdit`
2022-07-16 17:33:29 +02:00
Roy-043 e2ed278874 Draft: Fix Hatch task panel title
Form -> Hatch
2022-07-16 17:32:47 +02:00
Marshal Horn c97f1afd72 Replaced python2 usage of next()
iterator.next() is deprecated in python3.
next(iterator) is the direct replacement.
In some cases a for() loop makes more sense
2022-07-16 17:29:23 +02:00
Wanderer Fan 8d5f274d03 [TD]fix crash on body with no shape 2022-07-14 01:59:41 +02:00
Bernd Hahnebach bd2a9b259d FEM: Python code formatting 2022-07-14 01:56:54 +02:00
Uwe c68d109db1 [FEM] femutils.py: style changes
- as requested
2022-07-14 01:55:10 +02:00
Uwe c1bea323d2 [FEM] fix solver console bugs
- for Elmer and Z88 on Windows several windows pop up (console windows). This is maybe annoying and the user is wondering what is going on, but the main problem is that when you close them, you break the solving process.
Therefore, on Windows only, hide the empty popup windows.
2022-07-14 01:55:10 +02:00
sliptonic 179329d1ba Merge pull request #7137 from Russ4262/fix/path_array_polar
Path: Fix Type=Polar regression in PathArray
2022-07-14 01:51:40 +02:00
Uwe b0e55b69ed Merge pull request #7178 from sliptonic/bug/misc
[Path]  Several small bug fixes
2022-07-14 01:47:26 +02:00
Bernd Hahnebach fc13b150d5 FEM: elmer solver writer, add some comment in the regard of units 2022-07-14 01:37:30 +02:00
wmayer 9e3618005e Part: [skip ci] fix possible build failure 2022-07-14 01:34:26 +02:00
Peter Marquardt fcba255925 Draft: fix spacing of ToolTip text 2022-07-14 01:32:17 +02:00
Bernd Hahnebach f6e1aeabe3 FEM: typos, found with:
codespell -q 2 -S *.ts -S *.dyn -S *.svg  -L childs,dof,dum,freez,methode,nd,normaly,programm,som,uint,vertexes,inout  src/Mod/Fem/
2022-07-14 01:30:54 +02:00
Uwe bbc5ca8a74 [FEM] fix CCX multi-threading bug
- in the preferences one could specify more CPU cores than available

- also correct a label sine the number of cores are since FC 0.20 used for all CCX solver runs

- also remove unnecessary (doubled) slots from the UI file
2022-07-10 17:34:48 +02:00
Uwe 0e304cd22b [FEM] remove doubled slots from preferences UI files 2022-07-10 17:34:48 +02:00
wehrle cc55bf7d83 correction 2022-07-10 13:44:24 +02:00
Roy-043 9833f3fd99 Draft: Fix join.py 2022-07-09 20:17:31 +02:00
Wanderer Fan 6cd575600c [TD]fix bad edge in face finder 2022-07-09 20:15:50 +02:00
Benjamin Bræstrup Sayoc 23f39ad2da [TechDraw] Use function overloadin and avoid code repeat 2022-07-09 20:14:45 +02:00
wmayer 3dadeab9e0 GuiPy: allow to call setupWithoutGUI more than once 2022-07-09 20:12:41 +02:00
Roy-043 1861868428 Draft: displayStatusbarScaleWidget should be checked in preferences-draftinterface.ui 2022-07-09 20:11:18 +02:00
Roy-043 3ce1ce70c9 Arch: Invert opening symbol Simple door 2022-07-09 20:08:01 +02:00
Wanderer Fan 6e77b5ae3f [TD]fix multiple open dialogs 2022-07-09 19:43:31 +02:00
wmayer ebed2d0b33 Test: [skip ci] unit test for fix of Vector2d::Rotate 2022-07-09 19:41:46 +02:00
Wanderer Fan 74bbc3e1db [TD]fix scaling of bitmap 2022-07-09 19:35:49 +02:00
Yorik van Havre 020375256c Merge pull request #7122 from donovaly/Arch-fix-typo
[Arch] fix typo in function name
2022-07-09 19:33:02 +02:00
wmayer 323acb01cf App: fix build failure on Windows caused by PR #7034 2022-07-09 19:31:01 +02:00
flachyjoe 8bb7cfe780 [App] Fix file not found error with canonical filename
boost::filesystem::canonical doesn't resolve non existent file where
boost::filesystem::weakly_canonical does.

Notice boost::filesystem::weakly_canonical only resolve absolute path.
2022-07-09 19:29:48 +02:00
flachyjoe d25478bb35 [App] Fix #5592 : Respect symbolic links
Use the real path to the file when saving the document.
2022-07-09 19:29:48 +02:00
Wanderer Fan ed94b600ca [TD]fix bitmap hatch 2022-07-03 17:55:17 +02:00
Uwe ee78a3c046 [Base] Tools2D.h: a simplification and code style unification 2022-07-03 16:22:28 +02:00
ChenOrange 6a44d1e8ff Vector2d:fix rotate bug 2022-07-03 16:22:28 +02:00
luz paz cc90163850 LGTM: omit src/Tools/wiki2qhelp.py from analysis
Per https://lgtm.com/projects/g/FreeCAD/FreeCAD

[skip ci]
2022-07-03 16:22:02 +02:00
Uwe da1e2c22de [FEM] fix wrong console outputs for fluid materials
- since a while ThermalExpansionCoefficient is used, VolumetricThermalExpansionCoefficient is only used for the material task panel
- as already stated in a code comment, the unit of VolumetricThermalExpansionCoefficient is ThermalExpansionCoefficient, therefore we must check for ThermalExpansionCoefficient
- we must also check if ThermalExpansionCoefficient exists

- Adapt the existing fluid material cards to use the ThermalExpansionCoefficient
2022-07-03 16:17:10 +02:00
Mihail ed7c650f48 FEM WB Elmer viscosity bug fix.
In Elmer there was errors "Viscosity not found" if used mixed solid and flow calculation.
This fix disables Stokes-Navier eruation for Solid objects.

	modified:      src/Mod/Fem/femsolver/elmer/writer.py
2022-07-03 16:15:44 +02:00
Yorik van Havre ad181ce993 Merge pull request #7071 from Roy-043/Draft-Fix-Placement-in-make_sketch
Draft: Fix Sketch Placement in make_sketch (issue #7058)
2022-07-01 03:27:13 +02:00
Wanderer Fan c91c096235 [TD]fix Dimension export to DXF 2022-07-01 02:46:13 +02:00
Wanderer Fan c06f0e9132 [TD]Include CosmeticLines in Dxf 2022-07-01 02:46:13 +02:00
wmayer 5930aac110 Test: ignore UnicodeEncodeError in TestMetadata.test_file_path 2022-07-01 02:21:05 +02:00
wmayer 1d55d10a51 Test: use codecs.open in TestMetadata.test_file_path 2022-07-01 02:12:40 +02:00
wmayer 9a51cd0e34 App: issue #7112: Addon manager does not work on windows with special characters in the username 2022-07-01 02:02:44 +02:00
Roy-043 a0e5012ed0 Draft: Fix default fillmode in DraftGui.py 2022-07-01 02:01:44 +02:00
wmayer ad2c36b351 Test: [skip ci] test file path with utf-8 <-> utf-16 conversion 2022-06-30 00:33:30 +02:00
wmayer 4c74687a6d Test: extend test for enumeration 2022-06-30 00:31:32 +02:00
Roy-043 0d510a837f Draft: Fix align working plane to DatumPlane bug 2022-06-30 00:30:10 +02:00
Roy-043 c219656919 Draft: Fix align working plane to DatumPlane bug 2022-06-30 00:29:48 +02:00
wmayer bb6ab2d7c2 Part: fix GeomBSplineCurve::toBiArcs
If tangent of start and end point are parallel then also check a tangent in between to make sure that it can be considered a straight line
See https://forum.freecadweb.org/viewtopic.php?f=8&t=69710
2022-06-30 00:27:09 +02:00
Uwe ebb5a2bdc6 [FEM] fix point filter initialization issue
- on opening the task dialog of existing point filter, the point value must be displayed
2022-06-27 02:14:45 +02:00
sliptonic 7547f6c79b Merge pull request #6760 from Russ4262/fix/dressup_leadinout
Path: Fixes #6693 - Add Z and K values to arc commands
2022-06-25 19:23:44 +02:00
Uwe f4bf59e000 [PD] Hole initialization bugfix
- by default there is no hole head cut and therefore its parameter must be initialized as read-only (will be enably when user sets a head cut)

- also fix a typo

- also fix a UI file issue (automatically done by Qt Designer)
2022-06-25 16:59:19 +02:00
Kuzemko Alexsandr 79df3ea2eb [Part] Fix display "labelfillet" name for Chamfer and Fillet (#7083)
* Fix display "labelfillet" name for Chamfer and Fillet
* Synchronize options name with PartDesign_Chamfer. Proposed by  @Roy-043
@Roy-043 https://github.com/FreeCAD/FreeCAD/pull/7074#issuecomment-1165303970
2022-06-25 15:06:18 +02:00
Uwe d0c9fec938 [PD] Hole dialog fixes
- when there is no profile the change of the hole cut type was not handled
- for the deprecated hole cut types it must also be possible to use custom values
2022-06-25 14:12:06 +02:00
ShuffleWire de5e7f35e1 Base: add Const attribute to many MatrixPy methods
multiply(), determinant(), isOrthogonal(),
submatrix(), analyze() also get the const attribute
2022-06-24 02:38:20 +02:00
wmayer a015548a88 Part: add Const attribute to several methods in TopoShapePy 2022-06-24 02:38:20 +02:00
wmayer 8a56db68e7 Base: add Const attribute to MatrixPy::inverse() 2022-06-24 02:38:20 +02:00
Adrian Insaurralde Avalos 3f2df77d3f Rename FindOpenCasCade.cmake to FindOCC.cmake
To fix a warning 'name passed to `find_package_handle_standard_args` (OCC) does not match'
2022-06-24 02:37:40 +02:00
luzpaz bb51742f33 Stylesheets: fix typos
[skip ci]
2022-06-24 02:34:58 +02:00
wmayer d07ca8c3b6 Test: [skip ci] test for fixed Rotation::inverse() 2022-06-20 13:14:43 +02:00
marioalexis 763ba9e149 Base: Fix wrong function name in RotationPy documentation. 2022-06-20 02:20:46 +02:00
Uwe c62f6a7e4c Merge branch 'releases/FreeCAD-0-20' of github.com:FreeCAD/FreeCAD into releases/FreeCAD-0-20 2022-06-20 01:00:24 +02:00
Uwe 3e375b6528 update version number and copyright year 2022-06-20 01:00:05 +02:00
Christoph Moench-Tegeder 0a5a1803a5 fix Expressions assignment for FreeBSD
Just like Apple, FreeBSD uses clang as it's main compiler, and thus
runs afoul of the same problem in src/App/PropertyExpressionEngine.cpp
like Apple (issue #5281): "error: no viable overloaded '='".
Extend the fix from #5281 for the BSDs (check macro FC_OS_BSD) -
at least OpenBSD uses clang, too (maybe this check should be reworked
to test for clang, but I can't test on Apple, so let's keep this fix
minimalistic).

References: #5281
2022-06-19 16:15:02 +02:00
marioalexis be9218a76a Base: Set angle in Rotation::inverse function 2022-06-19 15:45:08 +02:00
Wanderer Fan e3865d5121 [TD]fix ProjGroup view spacing 2022-06-19 15:13:42 +02:00
Wanderer Fan 66d6379f7e [TD]fix dimension update on scale change 2022-06-19 15:13:41 +02:00
wmayer c7c9f630b3 plugin: do not exclude widget plugins from tarball 2022-06-19 15:09:22 +02:00
wmayer 6f0e049638 Mesh: fixes #6902: Conda test errors 2022-06-19 15:08:22 +02:00
wmayer 28f730a81e Mesh: fixes #7018: 3mf created with FreeCAD cannot be loaded with PrusaSlicer 2022-06-19 15:06:19 +02:00
wmayer 637472f105 Part: [skip ci] add tests for ruled surfaces 2022-06-19 15:04:16 +02:00
wmayer bd3d6aa3ed Spreadsheet: add tests for merging cells and binding cells 2022-06-19 15:02:42 +02:00
Uwe bcd43070b3 update screenshot in Readme
update screenshot to FC 0.20
2022-06-19 15:01:40 +02:00
TotalCaesar659 c6ab0be18e Update URL to HTTPS 2022-06-19 15:01:40 +02:00
Uwe 668570fc85 [Win installer] update information
- also refine a script
2022-06-19 15:01:40 +02:00
Uwe 3c565e1307 Update Readme to FreeCAD 0.20 2022-06-19 14:59:23 +02:00
1079 changed files with 26374 additions and 66976 deletions
-66
View File
@@ -1,66 +0,0 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: DontAlign
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: MultiLine
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 100
CompactNamespaces: false
ContinuationIndentWidth: 4
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never
+4 -6
View File
@@ -1,7 +1,5 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,boost-*,bugprone-*,
performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,
concurrency-*,-modernize-use-trailing-return-type, -modernize-use-nodiscard'
Checks: 'clang-diagnostic-*,clang-analyzer-*,boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,concurrency-*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
@@ -285,7 +283,7 @@ CheckOptions:
- key: readability-identifier-naming.AggressiveDependentMemberLookup
value: 'false'
- key: readability-identifier-length.MinimumParameterNameLength
value: '2'
value: '3'
- key: modernize-use-emplace.TupleTypes
value: '::std::pair;::std::tuple'
- key: modernize-use-emplace.TupleMakeFunctions
@@ -407,7 +405,7 @@ CheckOptions:
- key: portability-restrict-system-includes.Includes
value: '*'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: 'true'
value: 'false'
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
value: '<memory>'
- key: bugprone-signal-handler.AsyncSafeFunctionSet
@@ -419,7 +417,7 @@ CheckOptions:
- key: cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
value: 'false'
- key: readability-identifier-length.MinimumVariableNameLength
value: '2'
value: '3'
- key: cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
value: 'true'
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
+3 -5
View File
@@ -19,9 +19,7 @@ body:
id: forum_link
attributes:
label: Forums discussion
description: |
Please start a discussion about your issue at [the FreeCAD Forum](https://forum.freecad.org) and wait for confirmation there before creating an issue.
**Note:** Bug reports without a prior forum discussion will most likely not be accepted.
description: Please start a discussion about your issue at [the FreeCAD Forum](https://forum.freecad.org) and wait for confirmation there before creating an issue
placeholder: Paste link to forum discussion here
validations:
required: true
@@ -31,8 +29,8 @@ body:
label: Version
description: What version of FreeCAD are you running?
options:
- 0.20 (Release)
- 0.21 (Development)
- 0.19 (Release)
- 0.20 (Development)
validations:
required: true
- type: textarea
+1 -1
View File
@@ -9,6 +9,6 @@ Thank you for creating a pull request to contribute to FreeCAD! To ease integrat
- [ ] Commit messages include `issue #<id>` or `fixes #<id>` where `<id>` is the issue ID number from our [Issues database](https://github.com/FreeCAD/FreeCAD/issues) in case a particular commit solves or is related to an existing issue. Ex: `Draft: fix typos - fixes #4805`
And please remember to update the Wiki with the features added or changed once this PR is merged.
**Note**: If you don't have wiki access, then please mention your contribution on the [1.0 Changelog Forum Thread](https://forum.freecad.org/viewtopic.php?f=10&t=69438).
**Note**: If you don't have wiki access, then please mention your contribution on the [0.20 Changelog Forum Thread](https://forum.freecadweb.org/viewtopic.php?f=10&t=56135).
---
-4
View File
@@ -33,7 +33,6 @@ hist
indicies
inout
ist
itsel
lod
mantatory
mata
@@ -44,7 +43,6 @@ nin
normale
normaly
numer
oce
ontop
ot
parm
@@ -56,7 +54,6 @@ recurrance
rougly
seh
serie
siz
som
strack
substraction
@@ -65,7 +62,6 @@ te
thist
tread
ue
upto
uptodate
usind
vas
+3 -5
View File
@@ -3,7 +3,6 @@ on:
push:
branches: ['master', 'development/toponaming', 'releases/FreeCAD-0-20']
pull_request:
workflow_dispatch:
permissions:
pull-requests: write
@@ -36,14 +35,14 @@ env:
# This option allows you to specify a comma-separated list of rule-filters to apply. For example, the rule names look like whitespace/indent. In that case, the category is whitespace.
# To turn off, specify - as prefix like -whitespace or -whitespace/indent. On the other hand, to turn on, specify + like +whitespace or +whitespace/indent.
# The recommended filters are taken from https://github.com/sider/runners/blob/HEAD/images/cpplint/sider_recommended_CPPLINT.cfg
cpplintFilters: -build/c++11,-build/header_guard,-build/include,-build/include_alpha,-build/include_order,-build/include_subdir,-build/include_what_you_use,-build/namespaces,-legal/copyright,-readability/braces,-readability-braces-around-statements,-readability/casting,-readability/namespace,-readability/todo,-runtime/indentation_namespace,-runtime/int,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comma,-whitespace/comments,-whitespace/end_of_line,-whitespace/indent,-whitespace/line_length,-whitespace/newline,-whitespace/operators,-whitespace/parens,-whitespace/semicolon,-whitespace/tab,-whitespace/todo
cpplintFilters: -build/c++11,-build/header_guard,-build/include,-build/include_alpha,-build/include_order,-build/include_subdir,-build/include_what_you_use,-build/namespaces,-legal/copyright,-readability/braces,-readability/casting,-readability/namespace,-readability/todo,-runtime/int,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comments,-whitespace/end_of_line,-whitespace/indent,-whitespace/line_length,-whitespace/newline,-whitespace/operators,-whitespace/parens,-whitespace/tab,-whitespace/todo
cpplintLineLength: 120
cpplintFailSilent: true
checkPylint: true
# additional disables to the .pylintrc file
pylintDisable: # additional disables to the .pylintrc file
# for the Message codes see: https://pylint.pycqa.org/en/latest/user_guide/messages/index.html
pylintDisable: disable=C0302 # too-many-lines
pylintFailSilent: true
checkBlack: true
blackFailSilent: true
@@ -221,7 +220,6 @@ jobs:
echo "" >> ${{ env.logdir }}checkReport.md
- name: Harmonize Line endings
if: false #disabled because it causes failure when applied on .FCStd files
id: harmonize-line-endings
shell: bash
run: |
-31
View File
@@ -1,31 +0,0 @@
# GitHub Action to automate the identification of common misspellings in text files.
# https://github.com/codespell-project/actions-codespell
# https://github.com/codespell-project/codespell
name: Codespell
on:
pull_request:
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v12.2
- name: List all changed files
run: |
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
echo "$file was changed"
done
- uses: codespell-project/actions-codespell@master
with:
check_filenames: true
ignore_words_file: .github/codespellignore
skip: ./.git,*.po,*.ts,*.svg,./ChangeLog.txt,./src/3rdParty,./src/Mod/Assembly/App/opendcm,./src/CXX,./src/zipios++,./src/Base/swig*,./src/Mod/Robot/App/kdl_cp,./src/Mod/Import/App/SCL,./src/WindowsInstaller,./src/Doc/FreeCAD.uml,./build/
path: ${{ steps.changed-files.outputs.all_changed_files }}
+2
View File
@@ -1,6 +1,8 @@
# file types to ignore
.*
!/.gitignore
!/.travis/
!/.travis.yml
!/.clang-format
!/.git-blame-ignore-revs
!/.gitattributes
+5 -6
View File
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)
# relates to FindOpenGL module
# and cache variables OPENGL_gl_LIBRARY, OPENGL_glu_LIBRARY
if (POLICY CMP0072)
set(OpenGL_GL_PREFERENCE LEGACY)
cmake_policy(SET CMP0072 OLD)
endif(POLICY CMP0072)
find_program(CCACHE_PROGRAM ccache) #This check should occur before project()
@@ -17,11 +17,10 @@ project(FreeCAD)
set(PACKAGE_VERSION_NAME "Vulcan")
set(PACKAGE_VERSION_MAJOR "0")
set(PACKAGE_VERSION_MINOR "21")
set(PACKAGE_VERSION_PATCH "0")
set(PACKAGE_VERSION_SUFFIX "dev") # either "dev" for development snapshot or "" (empty string)
set(FREECAD_VERSION_PATCH "0") # number of patch release (e.g. "4" for the 0.18.4 release)
set(PACKAGE_VERSION_MINOR "20")
set(PACKAGE_VERSION_PATCH "1")
set(PACKAGE_VERSION_SUFFIX "") # either "dev" for development snapshot or "" (empty string)
set(FREECAD_VERSION_PATCH "1") # number of patch release (e.g. "4" for the 0.18.4 release)
set(FREECAD_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}")
set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

+2 -47
View File
@@ -1,50 +1,7 @@
<h6 align="center"><img src="FreeCAD-toponaming-logo.png"/></h6>
![Logo](https://www.freecadweb.org/images/logo.png)
<h1 align="center">FreeCAD Topological Naming (toponaming) Branch</h1>
### Your own 3D parametric modeler
### About
This branch is dedicated to integrating code that improves the [topological naming problem](https://wiki.freecad.org/Topological_naming_problem) in FreeCAD. There have been several attempts to address it over the years within FreeCAD. In reality, toponaming is an issue that no modern CAD software is fully immune to. This is because the solutions are complex.
Thanks to an independent developer named Zheng Lei ('realthunder'), who has gone the farthest in the effort of fixing toponaming in FreeCAD, and has provided a proof of concept fix in his own branch named 'Link' branch.
* [@Realthunder](https://github.com/realthunder)'s Link branch: https://github.com/realthunder/FreeCAD
* Official FreeCAD main ('master') branch: https://github.com/FreeCAD/FreeCAD/
* Official FreeCAD toponaming git repository: https://github.com/FreeCAD/FreeCAD/tree/development/toponaming
### Objective
Per the FreeCAD developer meetings that occurred during the pre-release of v0.20, 'toponaming' was identified as one of the main targets for merge in the v0.21/v1.0 release cycle.
### Contributing
During this development cycle there will be nightly builds provided for testers to test and report results back to the developers.
<details>
<summary>Expand this section to learn about testing toponaming on different platforms/distros</summary>
#### Linux
##### Snap packages
A nightly Snap package of the 'toponaming' branch will be available to testers. Refer to the [Snap wiki page](https://wiki.freecad.org/Ubuntu_Snap#Notes)
#### Windows
TBD
#### macOS
TBD
#### FreeBSD
N/A
</details>
<!--
[Website](https://www.freecadweb.org) •
[Documentation](https://wiki.freecadweb.org) •
[Forum](https://forum.freecadweb.org/) •
@@ -169,5 +126,3 @@ learning to use FreeCAD.
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="91px">
</a> and <a href="https://www.kipro-pcb.com/">KiCad Services Corp.</a>
</p>
-->
+9 -39
View File
@@ -5,55 +5,28 @@
# SMESH_INCLUDE_DIR - where the Salome SMESH include directory can be found
# SMESH_LIBRARIES - Link this to use Salome SMESH
#
# SMESH needs VTK
find_package(VTK REQUIRED)
# If this definition is not set, linker errors will occur against SMESH on 64 bit machines.
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(-DSALOME_USE_64BIT_IDS)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
IF (CMAKE_COMPILER_IS_GNUCC)
FIND_PATH(SMESH_INCLUDE_DIR SMESH_Mesh.hxx
# These are default search paths, why specify them?
PATH_SUFFIXES smesh SMESH smesh/SMESH
# /usr/include
# /usr/local/include
PATH_SUFFIXES smesh
)
FIND_LIBRARY(SMESH_LIBRARY SMESH
# /usr/lib
# /usr/local/lib
)
FIND_LIBRARY(SMESH_LIBRARY SMESH)
ELSE (CMAKE_COMPILER_IS_GNUCC)
# Not yet implemented
ENDIF (CMAKE_COMPILER_IS_GNUCC)
IF(SMESH_INCLUDE_DIR)
SET(SMESH_INC_ROOT "${SMESH_INCLUDE_DIR}/..")
# Append extra include dirs
SET(SMESH_INCLUDE_DIR
"${SMESH_INCLUDE_DIR};
${SMESH_INC_ROOT}/Controls;
${SMESH_INC_ROOT}/Driver;
${SMESH_INC_ROOT}/DriverDAT;
${SMESH_INC_ROOT}/DriverGMF;
${SMESH_INC_ROOT}/DriverSTL;
${SMESH_INC_ROOT}/DriverUNV;
${SMESH_INC_ROOT}/Geom;
${SMESH_INC_ROOT}/Kernel;
${SMESH_INC_ROOT}/MEFISTO2;
${SMESH_INC_ROOT}/MeshVSLink;
${SMESH_INC_ROOT}/Netgen;
${SMESH_INC_ROOT}/NETGENPlugin;
${SMESH_INC_ROOT}/SMDS;
${SMESH_INC_ROOT}/SMESHDS;
${SMESH_INC_ROOT}/SMESHUtils;
${SMESH_INC_ROOT}/StdMeshers;")
ELSE(SMESH_INCLUDE_DIR)
message(FATAL_ERROR "SMESH include directories not found!")
ENDIF(SMESH_INCLUDE_DIR)
SET(SMESH_FOUND FALSE)
IF(SMESH_LIBRARY)
SET(SMESH_FOUND TRUE)
GET_FILENAME_COMPONENT(SMESH_LIBRARY_DIR ${SMESH_LIBRARY} PATH)
set(SMESH_LIBRARIES
set(SMESH_LIBRARIES
${SMESH_LIBRARY_DIR}/libDriver.so
${SMESH_LIBRARY_DIR}/libDriverDAT.so
${SMESH_LIBRARY_DIR}/libDriverSTL.so
@@ -63,8 +36,5 @@ IF(SMESH_LIBRARY)
${SMESH_LIBRARY_DIR}/libSMESHDS.so
${SMESH_LIBRARY_DIR}/libStdMeshers.so
)
set(EXTERNAL_SMESH_LIBS ${SMESH_LIBRARIES})
ELSE(SMESH_LIBRARY)
message(FATAL_ERROR "SMESH libraries NOT FOUND!")
ENDIF(SMESH_LIBRARY)
@@ -37,5 +37,5 @@ macro(CheckInterModuleDependencies)
REQUIRES_MODS(BUILD_SKETCHER BUILD_PART)
REQUIRES_MODS(BUILD_SPREADSHEET BUILD_DRAFT)
REQUIRES_MODS(BUILD_START BUILD_WEB)
REQUIRES_MODS(BUILD_TECHDRAW BUILD_PART BUILD_SPREADSHEET)
REQUIRES_MODS(BUILD_TECHDRAW BUILD_PART BUILD_SPREADSHEET BUILD_DRAWING)
endmacro(CheckInterModuleDependencies)
@@ -10,7 +10,6 @@ macro(InitializeFreeCADBuildOptions)
option(FREECAD_USE_EXTERNAL_KDL "Use system installed orocos-kdl instead of the bundled." OFF)
option(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" ON)
option(FREECAD_BUILD_DEBIAN "Prepare for a build of a Debian package" OFF)
option(FREECAD_TOPONAMING_BRANDING "Enable branding for TopoNaming branch" ON)
option(BUILD_WITH_CONDA "Set ON if you build FreeCAD with conda" OFF)
option(BUILD_DYNAMIC_LINK_PYTHON "If OFF extension-modules do not link against python-libraries" ON)
option(INSTALL_TO_SITEPACKAGES "If ON the freecad root namespace (python) is installed into python's site-packages" OFF)
@@ -114,7 +113,7 @@ macro(InitializeFreeCADBuildOptions)
option(BUILD_ARCH "Build the FreeCAD Architecture module" ON)
option(BUILD_COMPLETE "Build the FreeCAD complete module" OFF)
option(BUILD_DRAFT "Build the FreeCAD draft module" ON)
option(BUILD_DRAWING "Build the FreeCAD drawing module" OFF)
option(BUILD_DRAWING "Build the FreeCAD drawing module" ON)
option(BUILD_IDF "Build the FreeCAD idf module" ON)
option(BUILD_IMAGE "Build the FreeCAD image module" ON)
option(BUILD_IMPORT "Build the FreeCAD import module" ON)
+8 -8
View File
@@ -27,7 +27,7 @@ macro(PrintFinalReport)
message(STATUS "pybind11: not enabled")
endif(DEFINED pybind11_FOUND)
message(STATUS "Boost: ${Boost_VERSION}")
message(STATUS "Boost: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION} (${Boost_VERSION})")
message(STATUS "XercesC: ${XercesC_VERSION} [${XercesC_LIBRARIES}] [${XercesC_INCLUDE_DIRS}]")
@@ -41,10 +41,10 @@ macro(PrintFinalReport)
if(FREECAD_USE_EXTERNAL_SMESH)
message(STATUS "SMESH: ${SMESH_VERSION_MAJOR}.${SMESH_VERSION_MINOR}.${SMESH_VERSION_PATCH}.${SMESH_VERSION_TWEAK}")
else(FREECAD_USE_EXTERNAL_SMESH)
message(STATUS "SMESH: ${SMESH_VERSION_MAJOR}.${SMESH_VERSION_MINOR}.${SMESH_VERSION_PATCH}.${SMESH_VERSION_TWEAK} build internal")
message(STATUS "MEDFile: ${MEDFILE_VERSION} [${MEDFILE_LIBRARIES}] [${MEDFILE_INCLUDE_DIRS}]")
message(STATUS "HDF5: ${HDF5_VERSION}")
message(STATUS "VTK: ${VTK_VERSION}")
message(STATUS "SMESH: build internal")
message(STATUS " MEDFile: ${MEDFILE_VERSION} [${MEDFILE_LIBRARIES}] [${MEDFILE_INCLUDE_DIRS}]")
message(STATUS " HDF5: ${HDF5_VERSION}")
message(STATUS " VTK: ${VTK_VERSION}")
endif(FREECAD_USE_EXTERNAL_SMESH)
else(BUILD_SMESH)
message(STATUS "SMESH: do not build")
@@ -191,11 +191,11 @@ macro(PrintFinalReport)
if(DOXYGEN_FOUND)
message(STATUS "Doxygen: ${DOXYGEN_VERSION}")
message(STATUS "Language: ${DOXYGEN_LANGUAGE}")
message(STATUS " Language: ${DOXYGEN_LANGUAGE}")
if(COIN3D_DOC_FOUND)
message(STATUS "Coin3D_DOC: found [${COIN3D_DOC_PATH}]")
message(STATUS " Coin3D_DOC: found [${COIN3D_DOC_PATH}]")
else(COIN3D_DOC_FOUND)
message(STATUS "Coin3D_DOC: not found")
message(STATUS " Coin3D_DOC: not found")
endif(COIN3D_DOC_FOUND)
else(DOXYGEN_FOUND)
message(STATUS "Doxygen: not found")
+5 -13
View File
@@ -119,21 +119,13 @@ macro(SetupSalomeSMESH)
else(NOT FREECAD_USE_EXTERNAL_SMESH)
find_package(SMESH CONFIG)
# If this definition is not set, linker errors will occur against SMESH on 64 bit machines.
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(-DSALOME_USE_64BIT_IDS)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(NOT SMESH_FOUND)
find_package(SMESH REQUIRED)
if(NOT SMESH_FOUND)
message(ERROR "================\n"
"SMESH not found.\n"
"================\n")
endif()
endif()
set (SMESH_INCLUDE_DIR ${SMESH_INCLUDE_PATH})
set(EXTERNAL_SMESH_LIBS ${SMESH_LIBRARIES})
if(NOT SMESH_FOUND)
message(ERROR "================\n"
"SMESH not found.\n"
"================\n")
endif()
include_directories(${SMESH_INCLUDE_DIR})
endif()
@@ -125,9 +125,7 @@ macro(SetupShibokenAndPyside)
"PySide2 Python module not found.\n"
"================================\n")
else()
message(STATUS "===============================================\n"
"PySide2 Python module found at ${PRINT_OUTPUT}.\n"
"===============================================\n")
message(STATUS "PySide2 Python module found at ${PRINT_OUTPUT}.\n")
endif()
endmacro(SetupShibokenAndPyside)
+1
View File
@@ -12,6 +12,7 @@ path_classifiers:
- "src/CXX/"
template:
- "src/Tools/examplePy2wiki.py"
- "src/Tools/wiki2qhelp.py"
- "src/Mode/TemplatePyMod/"
unmaintained:
- "src/Mod/Robot/"
+11 -10
View File
@@ -102,7 +102,6 @@
#include "OriginFeature.h"
#include "OriginGroupExtension.h"
#include "OriginGroupExtensionPy.h"
#include "StringHasherPy.h"
#include "Part.h"
#include "PartPy.h"
#include "Placement.h"
@@ -278,7 +277,6 @@ void Application::setupPythonTypes()
Base::Interpreter().addType(&Base::PlacementPy::Type, pAppModule, "Placement");
Base::Interpreter().addType(&Base::RotationPy::Type, pAppModule, "Rotation");
Base::Interpreter().addType(&Base::AxisPy::Type, pAppModule, "Axis");
Base::Interpreter().addType(&App::StringHasherPy::Type, pAppModule, "StringHasher");
// Note: Create an own module 'Base' which should provide the python
// binding classes from the base module. At a later stage we should
@@ -1906,9 +1904,6 @@ void Application::initTypes()
Data::ComplexGeoData ::init();
Data::Segment ::init();
App::StringID ::init();
App::StringHasher ::init();
// Properties
App ::Property ::init();
App ::PropertyContainer ::init();
@@ -2446,10 +2441,14 @@ void Application::initConfig(int argc, char ** argv)
// We only set these keys if not yet defined. Therefore it suffices to search
// only for 'BuildVersionMajor'.
if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) {
std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor;
std::stringstream str;
str << FCVersionMajor
<< "." << FCVersionMinor
<< "." << FCVersionPoint;
App::Application::Config()["ExeVersion" ] = str.str();
App::Application::Config()["BuildVersionMajor" ] = FCVersionMajor;
App::Application::Config()["BuildVersionMinor" ] = FCVersionMinor;
App::Application::Config()["BuildVersionPoint" ] = FCVersionPoint;
App::Application::Config()["BuildRevision" ] = FCRevision;
App::Application::Config()["BuildRepositoryURL" ] = FCRepositoryURL;
App::Application::Config()["BuildRevisionDate" ] = FCRevisionDate;
@@ -2468,8 +2467,6 @@ void Application::initConfig(int argc, char ** argv)
Branding brand;
QString binDir = QString::fromUtf8((mConfig["AppHomePath"] + "bin").c_str());
QFileInfo fi(binDir, QString::fromLatin1("branding.xml"));
if (!fi.exists())
fi = QFileInfo(binDir, QString::fromLatin1("branding_toponaming.xml"));
if (fi.exists() && brand.readFile(fi.absoluteFilePath())) {
Branding::XmlConfig cfg = brand.getUserDefines();
for (Branding::XmlConfig::iterator it = cfg.begin(); it != cfg.end(); ++it) {
@@ -2531,17 +2528,21 @@ void Application::initConfig(int argc, char ** argv)
// Remove banner if FreeCAD is invoked via the -c command as regular
// Python interpreter
if (!(mConfig["Verbose"] == "Strict"))
Console().Message("%s %s, Libs: %s.%sR%s\n%s",mConfig["ExeName"].c_str(),
Console().Message("%s %s, Libs: %s.%s.%sR%s\n%s",
mConfig["ExeName"].c_str(),
mConfig["ExeVersion"].c_str(),
mConfig["BuildVersionMajor"].c_str(),
mConfig["BuildVersionMinor"].c_str(),
mConfig["BuildVersionPoint"].c_str(),
mConfig["BuildRevision"].c_str(),
mConfig["CopyrightInfo"].c_str());
else
Console().Message("%s %s, Libs: %s.%sB%s\n",mConfig["ExeName"].c_str(),
Console().Message("%s %s, Libs: %s.%s.%sB%s\n",
mConfig["ExeName"].c_str(),
mConfig["ExeVersion"].c_str(),
mConfig["BuildVersionMajor"].c_str(),
mConfig["BuildVersionMinor"].c_str(),
mConfig["BuildVersionPoint"].c_str(),
mConfig["BuildRevision"].c_str());
}
LoadParameters();
+22 -19
View File
@@ -104,9 +104,9 @@ PyMethodDef Application::Methods[] = {
"* If no module is given it will be determined by the file extension.\n"
"* If more than one module can load a file the first one will be taken.\n"
"* If no module exists to load the file an exception will be raised."},
{"open", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
{"open", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
"See openDocument(string)"},
{"openDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
{"openDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sOpenDocument )), METH_VARARGS|METH_KEYWORDS,
"openDocument(filepath,hidden=False) -> object\n"
"Create a document and load the project file into the document.\n\n"
"filepath: file path to an existing file. If the file doesn't exist\n"
@@ -116,7 +116,7 @@ PyMethodDef Application::Methods[] = {
// {"saveDocument", (PyCFunction) Application::sSaveDocument, METH_VARARGS,
// "saveDocument(string) -- Save the document to a file."},
// {"saveDocumentAs", (PyCFunction) Application::sSaveDocumentAs, METH_VARARGS},
{"newDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( Application::sNewDocument )), METH_VARARGS|METH_KEYWORDS,
{"newDocument", reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) ()>( Application::sNewDocument )), METH_VARARGS|METH_KEYWORDS,
"newDocument(name, label=None, hidden=False, temp=False) -> object\n"
"Create a new document with a given name.\n\n"
"name: unique document name which is checked automatically.\n"
@@ -243,14 +243,14 @@ PyObject* Application::sOpenDocument(PyObject * /*self*/, PyObject *args, PyObje
char* Name;
PyObject *hidden = Py_False;
static char *kwlist[] = {"name","hidden",nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kwd, "et|O!", kwlist,
"utf-8", &Name, &PyBool_Type, &hidden))
if (!PyArg_ParseTupleAndKeywords(args, kwd, "et|O", kwlist,
"utf-8", &Name, &hidden))
return nullptr;
std::string EncodedName = std::string(Name);
PyMem_Free(Name);
try {
// return new document
return (GetApplication().openDocument(EncodedName.c_str(),PyObject_IsTrue(hidden) ? false : true)->getPyObject());
return (GetApplication().openDocument(EncodedName.c_str(),!PyObject_IsTrue(hidden))->getPyObject());
}
catch (const Base::Exception& e) {
PyErr_SetString(PyExc_IOError, e.what());
@@ -270,14 +270,14 @@ PyObject* Application::sNewDocument(PyObject * /*self*/, PyObject *args, PyObjec
PyObject *hidden = Py_False;
PyObject *temp = Py_False;
static char *kwlist[] = {"name","label","hidden","temp",nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kwd, "|etetO!O!", kwlist,
"utf-8", &docName, "utf-8", &usrName, &PyBool_Type, &hidden, &PyBool_Type, &temp))
if (!PyArg_ParseTupleAndKeywords(args, kwd, "|etetOO", kwlist,
"utf-8", &docName, "utf-8", &usrName, &hidden, &temp))
return nullptr;
PY_TRY {
App::Document* doc = GetApplication().newDocument(docName, usrName,
PyObject_IsTrue(hidden) ? false : true,
PyObject_IsTrue(temp) ? true : false);
!PyObject_IsTrue(hidden),
PyObject_IsTrue(temp));
PyMem_Free(docName);
PyMem_Free(usrName);
return doc->getPyObject();
@@ -317,7 +317,7 @@ PyObject* Application::sCloseDocument(PyObject * /*self*/, PyObject *args)
return nullptr;
}
if (!GetApplication().closeDocument(pstr)) {
if (GetApplication().closeDocument(pstr) == false) {
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", pstr);
return nullptr;
}
@@ -333,7 +333,7 @@ PyObject* Application::sSaveDocument(PyObject * /*self*/, PyObject *args)
Document* doc = GetApplication().getDocument(pDoc);
if ( doc ) {
if (!doc->save()) {
if ( doc->save() == false ) {
PyErr_Format(Base::PyExc_FC_GeneralError, "Cannot save document '%s'", pDoc);
return nullptr;
}
@@ -492,6 +492,9 @@ PyObject* Application::sGetVersion(PyObject * /*self*/, PyObject *args)
it = cfg.find("BuildVersionMinor");
list.append(Py::String(it != cfg.end() ? it->second : ""));
it = cfg.find("BuildVersionPoint");
list.append(Py::String(it != cfg.end() ? it->second : ""));
it = cfg.find("BuildRevision");
list.append(Py::String(it != cfg.end() ? it->second : ""));
@@ -701,7 +704,7 @@ PyObject* Application::sGetUserMacroPath(PyObject * /*self*/, PyObject *args)
return nullptr;
std::string macroDir = Application::getUserMacroDir();
if (PyObject_IsTrue(actual) ? true : false) {
if (PyObject_IsTrue(actual)) {
macroDir = App::GetApplication().
GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro")
->GetASCII("MacroPath",macroDir.c_str());
@@ -732,7 +735,7 @@ PyObject* Application::sGetHomePath(PyObject * /*self*/, PyObject *args)
PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args)
{
PyObject *sort = Py_False;
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
if (!PyArg_ParseTuple(args, "|O",&sort))
return nullptr;
PY_TRY {
PyObject *pDict = PyDict_New();
@@ -740,7 +743,7 @@ PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args)
Base::PyObjectBase* pValue;
std::vector<Document*> docs = GetApplication().getDocuments();;
if(PyObject_IsTrue(sort) ? true : false)
if(PyObject_IsTrue(sort))
docs = Document::getDependentDocuments(docs,true);
for (auto doc : docs) {
@@ -942,11 +945,11 @@ PyObject *Application::sSetActiveTransaction(PyObject * /*self*/, PyObject *args
{
char *name;
PyObject *persist = Py_False;
if (!PyArg_ParseTuple(args, "s|O!", &name, &PyBool_Type, &persist))
if (!PyArg_ParseTuple(args, "s|O", &name,&persist))
return nullptr;
PY_TRY {
Py::Int ret(GetApplication().setActiveTransaction(name,PyObject_IsTrue(persist) ? true : false));
Py::Int ret(GetApplication().setActiveTransaction(name,PyObject_IsTrue(persist)));
return Py::new_reference_to(ret);
}PY_CATCH;
}
@@ -972,11 +975,11 @@ PyObject *Application::sCloseActiveTransaction(PyObject * /*self*/, PyObject *ar
{
PyObject *abort = Py_False;
int id = 0;
if (!PyArg_ParseTuple(args, "|O!i", &PyBool_Type, &abort,&id))
if (!PyArg_ParseTuple(args, "|Oi", &abort,&id))
return nullptr;
PY_TRY {
GetApplication().closeActiveTransaction(PyObject_IsTrue(abort) ? true : false, id);
GetApplication().closeActiveTransaction(PyObject_IsTrue(abort),id);
Py_Return;
} PY_CATCH;
}
-1
View File
@@ -50,7 +50,6 @@ Branding::Branding()
filter.push_back("SplashAlignment");
filter.push_back("SplashTextColor");
filter.push_back("SplashInfoColor");
filter.push_back("SplashInfoVersion");
filter.push_back("StartWorkbench");
-12
View File
@@ -87,8 +87,6 @@ else()
)
endif()
generate_from_xml(StringIDPy)
generate_from_xml(StringHasherPy)
generate_from_xml(DocumentPy)
generate_from_xml(DocumentObjectPy)
generate_from_xml(ExtensionPy)
@@ -111,8 +109,6 @@ generate_from_py(FreeCADInit InitScript.h)
generate_from_py(FreeCADTest TestScript.h)
SET(FreeCADApp_XML_SRCS
StringIDPy.xml
StringHasherPy.xml
ExtensionPy.xml
ExtensionContainerPy.xml
DocumentObjectExtensionPy.xml
@@ -135,11 +131,7 @@ SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS})
# The document stuff
SET(Document_CPP_SRCS
Annotation.cpp
StringHasher.cpp
StringHasherPyImp.cpp
StringIDPyImp.cpp
Document.cpp
DocumentParams.cpp
DocumentObject.cpp
Extension.cpp
ExtensionPyImp.cpp
@@ -186,9 +178,7 @@ SET(Document_CPP_SRCS
SET(Document_HPP_SRCS
Annotation.h
StringHasher.h
Document.h
DocumentParams.h
DocumentObject.h
Extension.h
ExtensionContainer.h
@@ -273,7 +263,6 @@ SET(FreeCADApp_CPP_SRCS
AutoTransaction.cpp
Branding.cpp
ColorModel.cpp
MappedElement.cpp
ComplexGeoData.cpp
ComplexGeoDataPyImp.cpp
Enumeration.cpp
@@ -290,7 +279,6 @@ SET(FreeCADApp_HPP_SRCS
AutoTransaction.h
Branding.h
ColorModel.h
MappedElement.h
ComplexGeoData.h
Enumeration.h
Material.h
+16 -2104
View File
File diff suppressed because it is too large Load Diff
+2 -269
View File
@@ -24,17 +24,9 @@
#ifndef _AppComplexGeoData_h_
#define _AppComplexGeoData_h_
#include <cstring>
#include <memory>
#include <cctype>
#include <functional>
#include <QVector>
#include <Base/Handle.h>
#include <Base/Matrix.h>
#include <Base/Persistence.h>
#include "StringHasher.h"
#ifdef __GNUC__
# include <cstdint>
@@ -52,16 +44,6 @@ typedef BoundBox3<double> BoundBox3d;
namespace Data
{
class ElementMap;
typedef std::shared_ptr<ElementMap> ElementMapPtr;
typedef QVector<App::StringIDRef> ElementIDRefs;
class IndexedName;
class MappedName;
struct MappedElement;
struct MappedChildElements;
/** Segments
* Subelement type of the ComplexGeoData type
* It is used to split an object in further sub-parts.
@@ -101,7 +83,7 @@ public:
* List of different subelement types
* its NOT a list of the subelements itself
*/
virtual const std::vector<const char*>& getElementTypes() const=0;
virtual std::vector<const char*> getElementTypes() const=0;
virtual unsigned long countSubElements(const char* Type) const=0;
/// get the subelement by type and number
virtual Segment* getSubElement(const char* Type, unsigned long) const=0;
@@ -183,12 +165,8 @@ public:
//@{
/// Special prefix to mark the beginning of a mapped sub-element name
static const std::string &elementMapPrefix();
/// Special postfix to mark the following tag encoded as hex number
/// Special postfix to mark the following tag
static const std::string &tagPostfix();
/// Special postfix to mark the following tag encoded as decimal number
static const std::string &decTagPostfix();
/// Special postfix to mark the name includes encoding from an external object
static const std::string &externalTagPostfix();
/// Special postfix to mark the index of an array element
static const std::string &indexPostfix();
/// Special prefix to mark a missing element
@@ -213,246 +191,12 @@ public:
/// Find the start of an element name in a subname
static const char *findElementName(const char *subname);
/// Check if the given subname contains element name
static bool hasElementName(const char *subname) {
subname = findElementName(subname);
return subname && *subname;
}
/// Return the element name portion of the subname without mapping prefix
static inline const char *hasMappedElementName(const char *subname) {
return isMappedElement(findElementName(subname));
}
/** Get element indexed name
*
* @param name: the input name
* @param sid: optional output of and App::StringID involved forming this mapped name
*
* @return Returns an indexed name.
*/
IndexedName getIndexedName(const MappedName & name,
ElementIDRefs *sid = nullptr) const;
/** Get element mapped name
*
* @param name: the input name
* @param allowUnmapped: If the queried element is not mapped, then return
* an empty name if \c allowUnmapped is false, or
* else, return the indexed name.
* @param sid: optional output of and App::StringID involved forming this mapped name
* @return Returns the mapped name.
*/
MappedName getMappedName(const IndexedName & element,
bool allowUnmapped = false,
ElementIDRefs *sid = nullptr) const;
/** Return a pair of indexed name and mapped name
*
* @param name: the input name.
* @param sid: optional output of and App::StringID involved forming this
* mapped name
* @param copy: if true, copy the name string, or else use it as constant
* string, and caller must make sure the memory is not freed.
*
* @return Returns the MappedElement which contains both the indexed and
* mapped name.
*
* This function guesses whether the input name is an indexed name or
* mapped, and perform a lookup and return the names found. If the input
* name contains only alphabets and underscore followed by optional digits,
* it will be treated as indexed name. Or else, it will be treated as
* mapped name.
*/
MappedElement getElementName(const char * name,
ElementIDRefs *sid = nullptr,
bool copy = false) const;
/** Get mapped element with a given prefix */
std::vector<MappedElement> getElementNamesWithPrefix(const char *prefix) const;
/** Get mapped element names
*
* @param element: original element name with \c Type + \c Index
* @param needUnmapped: if true, return the original element name if no
* mapping is found
*
* @return a list of mapped names of the give element along with their
* associated string ID references
*/
std::vector<std::pair<MappedName, ElementIDRefs> >
getElementMappedNames(const IndexedName & element, bool needUnmapped=false) const;
/** Add a sub-element name mapping.
*
* @param element: the original \c Type + \c Index element name
* @param name: the mapped sub-element name. May or may not start with
* elementMapPrefix().
* @param sid: in case you use a hasher to hash the element name, pass in
* the string id reference using this parameter. You can have more than one
* string id associated with the same name.
* @param overwrite: if true, it will overwrite existing names
*
* @return Returns the stored mapped element name.
*
* An element can have multiple mapped names. However, a name can only be
* mapped to one element
*/
MappedName setElementName(const IndexedName & element,
const MappedName & name,
const ElementIDRefs * sid = nullptr,
bool overwrite = false);
void setMappedChildElements(const std::vector<MappedChildElements> & children);
std::vector<MappedChildElements> getMappedChildElements() const;
/** Convenience method to hash the main element name
*
* @param name: main element name
* @param sid: store any output string ID references
* @return the hashed element name;
*/
MappedName hashElementName(const MappedName & name, ElementIDRefs &sid) const;
/// Hash the child element map postfixes to shorten element name from hierarchical maps
void hashChildMaps();
/// Check if there is child element map
bool hasChildElementMap() const;
/// Reverse hashElementName()
MappedName dehashElementName(const MappedName & name) const;
/// Append the Tag (if and only if it is non zero) into the element map
virtual void reTagElementMap(long tag, App::StringHasherRef hasher, const char *postfix=0) {
(void)tag;
(void)hasher;
(void)postfix;
}
long getElementHistory(const char *name,
MappedName *original=0, std::vector<MappedName> *history=0) const;
long getElementHistory(const MappedName & name,
MappedName *original=0, std::vector<MappedName> *history=0) const;
void encodeElementName(char element_type, MappedName & name, std::ostringstream &ss,
ElementIDRefs *sids, const char* postfix=0, long tag=0, bool forceTag=false) const;
char elementType(const Data::MappedName &) const;
char elementType(const Data::IndexedName &) const;
char elementType(const char *name) const;
/** Reset/swap the element map
*
* @param elementMap: optional new element map
*
* @return Returns the existing element map.
*/
virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap=ElementMapPtr()) {
_ElementMap.swap(elementMap);
return elementMap;
}
/// Get the entire element map
std::vector<MappedElement> getElementMap() const;
/// Set the entire element map
void setElementMap(const std::vector<MappedElement> &elements);
/// Get the current element map size
size_t getElementMapSize(bool flush=true) const;
/// Return the higher level element names of the given element
virtual std::vector<IndexedName> getHigherElements(const char *name, bool silent=false) const;
/// Return the current element map version
virtual std::string getElementMapVersion() const;
/// Return true to signal element map version change
virtual bool checkElementMapVersion(const char * ver) const;
/// Check if the given subname only contains an element name
static bool isElementName(const char *subname) {
return subname && *subname && findElementName(subname)==subname;
}
/** Extract tag and other information from a encoded element name
*
* @param name: encoded element name
* @param tag: optional pointer to receive the extracted tag
* @param len: optional pointer to receive the length field after the tag field.
* This gives the length of the previous hashsed element name starting
* from the beginning of the give element name.
* @param postfix: optional pointer to receive the postfix starting at the found tag field.
* @param type: optional pointer to receive the element type character
* @param negative: return negative tag as it is. If disabled, then always return positive tag.
* Negative tag is sometimes used for element disambiguation.
* @param recursive: recursively find the last non-zero tag
*
* @return Return the end position of the tag field, or return -1 if not found.
*/
static int findTagInElementName(const MappedName & name,
long *tag=0,
int *len=0,
std::string *postfix=0,
char *type=0,
bool negative=false,
bool recursive=true);
/** Element trace callback
*
* The callback has the following call signature
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
*
* @param name: the current element name.
* @param offset: the offset skipping the encoded element name for the next iteration.
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
* of the previous step in the shape history.
* @param tag: the tag of the current shape element.
*
* @sa traceElement()
*/
typedef std::function<bool(const MappedName &, int, long, long)> TraceCallback;
/** Iterate through the history of the give element name with a given callback
*
* @param name: the input element name
* @param cb: trace callback with call signature.
* @sa TraceCallback
*/
void traceElement(const MappedName &name, TraceCallback cb) const;
/** Flush an internal buffering for element mapping */
virtual void flushElementMap() const;
virtual unsigned long getElementMapReserve() const { return 0; }
//@}
/** @name Save/restore */
//@{
void Save (Base::Writer &writer) const;
void Restore(Base::XMLReader &reader);
void SaveDocFile(Base::Writer &writer) const;
void RestoreDocFile(Base::Reader &reader);
unsigned int getMemSize (void) const;
void setPersistenceFileName(const char *name) const;
virtual void beforeSave() const;
bool isRestoreFailed() const { return _restoreFailed; }
void resetRestoreFailure() const { _restoreFailed = true; }
//@}
public:
/// String hasher for element name shortening
mutable App::StringHasherRef Hasher;
protected:
virtual MappedName renameDuplicateElement(int index,
const IndexedName & element,
const IndexedName & element2,
const MappedName & name,
ElementIDRefs &sids);
void restoreStream(std::istream &s, std::size_t count);
/// from local to outside
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
@@ -471,19 +215,8 @@ protected:
static_cast<float>(tmp.y),
static_cast<float>(tmp.z));
}
public:
mutable long Tag;
protected:
ElementMapPtr elementMap(bool flush=true) const;
protected:
mutable std::string _PersistenceName;
mutable bool _restoreFailed = false;
private:
ElementMapPtr _ElementMap;
};
} //namespace App
-61
View File
@@ -64,37 +64,6 @@
<UserDocu>Apply a transformation to the underlying geometry</UserDocu>
</Documentation>
</Methode>
<Methode Name="setElementName" Keyword="true">
<Documentation>
<UserDocu>
setElementName(element,name=None,postfix=None,overwrite=False,sid=None), Set an element name
element : the original element name, e.g. Edge1, Vertex2
name : the new name for the element, None to remove the mapping
postfix : postfix of the name that will not be hashed
overwrite: if true, it will overwrite exiting name
sid : to hash the name any way you want, provide your own string id(s) in this parameter
An element can have multiple mapped names. However, a name can only be mapped
to one element
</UserDocu>
</Documentation>
</Methode>
<Methode Name="getElementName" Const="true">
<Documentation>
<UserDocu>getElementName(name,direction=0) - Return a mapped element name or reverse</UserDocu>
</Documentation>
</Methode>
<Methode Name="getElementIndexedName" Const="true">
<Documentation>
<UserDocu>getElementIndexedName(name) - Return the indexed element name</UserDocu>
</Documentation>
</Methode>
<Methode Name="getElementMappedName" Const="true">
<Documentation>
<UserDocu>getElementMappedName(name) - Return the mapped element name</UserDocu>
</Documentation>
</Methode>
<Attribute Name="BoundBox" ReadOnly="true">
<Documentation>
<UserDocu>Get the BoundBox of the object</UserDocu>
@@ -119,35 +88,5 @@ to one element
</Documentation>
<Parameter Name="Tag" Type="Int"/>
</Attribute>
<Attribute Name="Hasher">
<Documentation>
<UserDocu>Get/Set the string hasher of this object</UserDocu>
</Documentation>
<Parameter Name="Hasher" Type="Object" />
</Attribute>
<Attribute Name="ElementMapSize" ReadOnly="true">
<Documentation>
<UserDocu>Get the current element map size</UserDocu>
</Documentation>
<Parameter Name="ElementMapSize" Type="Int" />
</Attribute>
<Attribute Name="ElementMap">
<Documentation>
<UserDocu>Get/Set a dict of element mapping</UserDocu>
</Documentation>
<Parameter Name="ElementMap" Type="Dict" />
</Attribute>
<Attribute Name="ElementReverseMap" ReadOnly="true">
<Documentation>
<UserDocu>Get a dict of element reverse mapping</UserDocu>
</Documentation>
<Parameter Name="ElementReverseMap" Type="Dict" />
</Attribute>
<Attribute Name="ElementMapVersion" ReadOnly="true">
<Documentation>
<UserDocu>Element map version</UserDocu>
</Documentation>
<Parameter Name="ElementMapVersion" Type="String" />
</Attribute>
</PythonExport>
</GenerateModel>
+3 -187
View File
@@ -27,7 +27,6 @@
#endif
#include "ComplexGeoData.h"
#include "MappedElement.h"
// inclusion of the generated files (generated out of ComplexGeoDataPy.xml)
#include <App/ComplexGeoDataPy.h>
@@ -37,8 +36,6 @@
#include <Base/PlacementPy.h>
#include <Base/VectorPy.h>
#include <Base/GeometryPyCXX.h>
#include <App/StringHasherPy.h>
#include <App/StringIDPy.h>
using namespace Data;
using namespace Base;
@@ -54,9 +51,10 @@ PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
if (!PyArg_ParseTuple(args, ""))
return nullptr;
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
Py::List list;
for (const auto &type : getComplexGeoDataPtr()->getElementTypes()) {
list.append(Py::String(type));
for (auto it : types) {
list.append(Py::String(it));
}
return Py::new_reference_to(list);
}
@@ -304,183 +302,6 @@ PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
}
}
PyObject* ComplexGeoDataPy::getElementName(PyObject *args)
{
char* input;
int direction = 0;
if (!PyArg_ParseTuple(args, "s|i", &input,&direction))
return NULL;
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(input);
std::string s;
if (direction == 1)
return Py::new_reference_to(Py::String(res.name.toString(s)));
else if (direction == 0)
return Py::new_reference_to(Py::String(res.index.toString(s)));
else if (Data::IndexedName(input))
return Py::new_reference_to(Py::String(res.name.toString(s)));
else
return Py::new_reference_to(Py::String(res.index.toString(s)));
}
PyObject* ComplexGeoDataPy::getElementIndexedName(PyObject *args)
{
char* input;
PyObject *returnID = Py_False;
if (!PyArg_ParseTuple(args, "s|O", &input,&returnID))
return NULL;
ElementIDRefs ids;
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(
input, PyObject_IsTrue(returnID)?&ids:nullptr);
std::string s;
Py::String name(res.index.toString(s));
if (!PyObject_IsTrue(returnID))
return Py::new_reference_to(name);
Py::List list;
for (auto &id : ids)
list.append(Py::Long(id.value()));
return Py::new_reference_to(Py::TupleN(name, list));
}
PyObject* ComplexGeoDataPy::getElementMappedName(PyObject *args)
{
char* input;
PyObject *returnID = Py_False;
if (!PyArg_ParseTuple(args, "s|O", &input,&returnID))
return NULL;
ElementIDRefs ids;
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(
input, PyObject_IsTrue(returnID)?&ids:nullptr);
std::string s;
Py::String name(res.name.toString(s));
if (!PyObject_IsTrue(returnID))
return Py::new_reference_to(name);
Py::List list;
for (auto &id : ids)
list.append(Py::Long(id.value()));
return Py::new_reference_to(Py::TupleN(name, list));
}
PyObject *ComplexGeoDataPy::setElementName(PyObject *args, PyObject *kwds) {
const char *element;
const char *name = 0;
const char *postfix = 0;
int tag = 0;
PyObject *pySid = Py_None;
PyObject *overwrite = Py_False;
static char *kwlist[] = {"element", "name", "postfix", "overwrite", "sid", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|sssOOi", kwlist,
&element,&name,&postfix,&overwrite,&pySid,&tag))
return NULL;
ElementIDRefs sids;
if(pySid != Py_None) {
if(PyObject_TypeCheck(pySid,&App::StringIDPy::Type))
sids.push_back(static_cast<App::StringIDPy*>(pySid)->getStringIDPtr());
else if(PySequence_Check(pySid)) {
Py::Sequence seq(pySid);
for(auto it=seq.begin();it!=seq.end();++it) {
auto ptr = (*it).ptr();
if(PyObject_TypeCheck(ptr,&App::StringIDPy::Type))
sids.push_back(static_cast<App::StringIDPy*>(ptr)->getStringIDPtr());
else
throw Py::TypeError("expect StringID in sid sequence");
}
} else
throw Py::TypeError("expect sid to contain either StringID or sequence of StringID");
}
PY_TRY {
Data::IndexedName index(element, getComplexGeoDataPtr()->getElementTypes());
Data::MappedName mapped = Data::MappedName::fromRawData(name);
std::ostringstream ss;
getComplexGeoDataPtr()->encodeElementName(getComplexGeoDataPtr()->elementType(index),
mapped, ss, &sids, postfix, tag);
Data::MappedName res = getComplexGeoDataPtr()->setElementName(
index, mapped, &sids, PyObject_IsTrue(overwrite));
return Py::new_reference_to(Py::String(res.toString(0)));
}PY_CATCH
}
Py::Object ComplexGeoDataPy::getHasher() const {
auto self = getComplexGeoDataPtr();
if(!self->Hasher)
return Py::None();
return Py::Object(self->Hasher->getPyObject(),true);
}
Py::Dict ComplexGeoDataPy::getElementMap() const {
Py::Dict ret;
std::string s;
for(auto &v : getComplexGeoDataPtr()->getElementMap()) {
s.clear();
ret.setItem(v.name.toString(0), Py::String(v.index.toString(s)));
}
return ret;
}
void ComplexGeoDataPy::setElementMap(Py::Dict dict) {
std::vector<Data::MappedElement> map;
const auto & types = getComplexGeoDataPtr()->getElementTypes();
for(auto it=dict.begin();it!=dict.end();++it) {
const auto &value = *it;
if(!value.first.isString() || !value.second.isString())
throw Py::TypeError("expect only strings in the dict");
map.emplace_back(Data::MappedName(value.first.as_string().c_str()),
Data::IndexedName(Py::Object(value.second).as_string().c_str(), types));
}
getComplexGeoDataPtr()->setElementMap(map);
}
Py::Dict ComplexGeoDataPy::getElementReverseMap() const {
Py::Dict ret;
std::string s;
for(auto &v : getComplexGeoDataPtr()->getElementMap()) {
s.clear();
auto value = ret[Py::String(v.index.toString(s))];
Py::Object item(value);
if(item.isNone()) {
s.clear();
value = Py::String(v.name.toString(s));
} else if(item.isList()) {
Py::List list(item);
s.clear();
list.append(Py::String(v.name.toString(s)));
} else {
Py::List list;
list.append(item);
s.clear();
list.append(Py::String(v.name.toString(s)));
value = list;
}
}
return ret;
}
Py::Int ComplexGeoDataPy::getElementMapSize() const {
return Py::Int((long)getComplexGeoDataPtr()->getElementMapSize());
}
void ComplexGeoDataPy::setHasher(Py::Object obj) {
auto self = getComplexGeoDataPtr();
if(obj.isNone()) {
if(self->Hasher) {
self->Hasher = App::StringHasherRef();
self->resetElementMap();
}
}else if(PyObject_TypeCheck(obj.ptr(),&App::StringHasherPy::Type)) {
App::StringHasherRef ref(static_cast<App::StringHasherPy*>(obj.ptr())->getStringHasherPtr());
if(self->Hasher != ref) {
self->Hasher = ref;
self->resetElementMap();
}
}else
throw Py::TypeError("invalid type");
}
Py::Object ComplexGeoDataPy::getBoundBox() const
{
return Py::BoundingBox(getComplexGeoDataPtr()->getBoundBox());
@@ -513,11 +334,6 @@ void ComplexGeoDataPy::setPlacement(Py::Object arg)
}
}
Py::String ComplexGeoDataPy::getElementMapVersion() const
{
return Py::String(getComplexGeoDataPtr()->getElementMapVersion());
}
Py::Int ComplexGeoDataPy::getTag() const
{
return Py::Int(getComplexGeoDataPtr()->Tag);
+55 -225
View File
@@ -65,7 +65,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include <boost/algorithm/string.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/bimap.hpp>
#include <boost/graph/strong_components.hpp>
#ifdef USE_OLD_DAG
@@ -96,7 +95,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include <Base/Stream.h>
#include "Document.h"
#include "DocumentParams.h"
#include "Application.h"
#include "AutoTransaction.h"
#include "DocumentObserver.h"
@@ -108,7 +106,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include "MergeDocuments.h"
#include "Origin.h"
#include "OriginGroupExtension.h"
#include "StringHasher.h"
#include "Transactions.h"
#ifdef _MSC_VER
@@ -119,6 +116,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include <zipios++/zipoutputstream.h>
#include <zipios++/meta-iostreams.h>
FC_LOG_LEVEL_INIT("App", true, true, true)
using Base::Console;
@@ -153,10 +151,8 @@ typedef std::vector <size_t> Path;
namespace App {
typedef boost::bimap<StringHasherRef,int> HasherMap;
static bool _IsRestoring;
static bool _IsRelabeling;
// Pimpl class
struct DocumentP
{
@@ -182,7 +178,6 @@ struct DocumentP
unsigned int UndoMemSize;
unsigned int UndoMaxStackSize;
std::string programVersion;
mutable HasherMap hashers;
#ifdef USE_OLD_DAG
DependencyList DepList;
std::map<DocumentObject*,Vertex> VertexObjectList;
@@ -191,15 +186,7 @@ struct DocumentP
std::multimap<const App::DocumentObject*,
std::unique_ptr<App::DocumentObjectExecReturn> > _RecomputeLog;
StringHasherRef Hasher;
// restored files
std::set<std::string> files;
DocumentP() {
#ifdef FC_NO_RANDOM_ID
lastObjectId = 10;
#else
static std::random_device _RD;
static std::mt19937 _RGEN(_RD());
static std::uniform_int_distribution<> _RDIST(0,5000);
@@ -207,8 +194,6 @@ struct DocumentP
// copying shape from other document. It is probably better to randomize
// on each object ID.
lastObjectId = _RDIST(_RGEN);
#endif
Hasher.reset(new StringHasher);
activeObject = nullptr;
activeUndoTransaction = nullptr;
iTransactionMode = 0;
@@ -1481,6 +1466,7 @@ void Document::onChanged(const Property* prop)
// the Name property is a label for display purposes
if (prop == &Label) {
Base::FlagToggler<> flag(_IsRelabeling);
App::GetApplication().signalRelabelDocument(*this);
} else if(prop == &ShowHidden) {
App::GetApplication().signalShowHidden(*this);
@@ -1515,12 +1501,6 @@ void Document::onChanged(const Property* prop)
// recursive call of onChanged()
this->Uid.setValue(id);
}
} else if(prop == &UseHasher) {
for(auto obj : d->objectArray) {
auto geofeature = dynamic_cast<GeoFeature*>(obj);
if(geofeature && geofeature->getPropertyOfGeometry())
geofeature->enforceRecompute();
}
}
}
@@ -1528,8 +1508,8 @@ void Document::onBeforeChangeProperty(const TransactionalObject *Who, const Prop
{
if(Who->isDerivedFrom(App::DocumentObject::getClassTypeId()))
signalBeforeChangeObject(*static_cast<const App::DocumentObject*>(Who), *What);
if(!d->rollback) {
_checkTransaction(nullptr, What, __LINE__);
if(!d->rollback && !_IsRelabeling) {
_checkTransaction(nullptr,What,__LINE__);
if (d->activeUndoTransaction)
d->activeUndoTransaction->addObjectChange(Who,What);
}
@@ -1564,8 +1544,10 @@ Document::Document(const char *name)
Console().Log("+App::Document: %p\n",this);
#endif
std::string CreationDateString = Base::TimeInfo::currentDateTimeString();
std::string Author = DocumentParams::getprefAuthor();
std::string AuthorComp = DocumentParams::getprefCompany();
std::string Author = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefAuthor","");
std::string AuthorComp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefCompany","");
ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document");
ADD_PROPERTY_TYPE(FileName,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),"The path to the file where the document is saved to");
ADD_PROPERTY_TYPE(CreatedBy,(Author.c_str()),0,Prop_None,"The creator of the document");
@@ -1586,7 +1568,8 @@ Document::Document(const char *name)
ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract");
// license stuff
int licenseId = DocumentParams::getprefLicenseType();
int licenseId = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetInt("prefLicenseType",0);
std::string license;
std::string licenseUrl;
switch (licenseId) {
@@ -1631,17 +1614,13 @@ Document::Document(const char *name)
break;
}
if(DocumentParams::getprefLicenseUrl().empty())
licenseUrl = DocumentParams::getprefLicenseUrl();
licenseUrl = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefLicenseUrl", licenseUrl.c_str());
ADD_PROPERTY_TYPE(License,(license.c_str()),0,Prop_None,"License string of the Item");
ADD_PROPERTY_TYPE(LicenseURL,(licenseUrl.c_str()),0,Prop_None,"URL to the license text/contract");
ADD_PROPERTY_TYPE(ShowHidden,(false), 0,PropertyType(Prop_None),
"Whether to show hidden object items in the tree view");
ADD_PROPERTY_TYPE(UseHasher,(true), 0,PropertyType(Prop_Hidden),
"Whether to use hasher on topological naming");
if(!DocumentParams::getUseHasher())
UseHasher.setValue(false);
// this creates and sets 'TransientDir' in onChanged()
ADD_PROPERTY_TYPE(TransientDir,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),
@@ -1711,31 +1690,11 @@ std::string Document::getTransientDirectoryName(const std::string& uuid, const s
void Document::Save (Base::Writer &writer) const
{
d->hashers.clear();
addStringHasher(d->Hasher);
writer.Stream() << "<Document SchemaVersion=\"4\" ProgramVersion=\""
<< App::Application::Config()["BuildVersionMajor"] << "."
<< App::Application::Config()["BuildVersionMinor"] << "R"
<< App::Application::Config()["BuildRevision"]
<< "\" FileVersion=\"" << writer.getFileVersion()
<< "\" Uid=\"" << Uid.getValueStr()
<< "\" StringHasher=\"1\">\n";
writer.incInd();
if (writer.isForceXML())
d->Hasher->setPersistenceFileName(0);
else
d->Hasher->setPersistenceFileName("StringHasher.Table");
for (auto o : d->objectArray)
o->beforeSave();
beforeSave();
d->Hasher->Save(writer);
writer.decInd();
<< "\" FileVersion=\"" << writer.getFileVersion() << "\">" << endl;
PropertyContainer::Save(writer);
@@ -1747,12 +1706,7 @@ void Document::Save (Base::Writer &writer) const
void Document::Restore(Base::XMLReader &reader)
{
int i,Cnt;
d->hashers.clear();
d->touchedObjs.clear();
addStringHasher(d->Hasher);
Base::ReaderContext rctx(getName());
setStatus(Document::PartialDoc,false);
reader.readElement("Document");
@@ -1769,11 +1723,6 @@ void Document::Restore(Base::XMLReader &reader)
reader.FileVersion = 0;
}
if (reader.hasAttribute("StringHasher")) {
Base::ReaderContext rctx("StringHasher");
d->Hasher->Restore(reader);
} else
d->Hasher->clear();
// When this document was created the FileName and Label properties
// were set to the absolute path or file name, respectively. To save
// the document to the file it was loaded from or to show the file name
@@ -1816,7 +1765,6 @@ void Document::Restore(Base::XMLReader &reader)
for (i=0 ;i<Cnt ;i++) {
reader.readElement("Feature");
string name = reader.getAttribute("name");
Base::ReaderContext rctx(name);
DocumentObject* pObj = getObject(name.c_str());
if (pObj) { // check if this feature has been registered
pObj->setStatus(ObjectStatus::Restore, true);
@@ -1839,36 +1787,6 @@ void Document::Restore(Base::XMLReader &reader)
reader.readEndElement("Document");
}
std::pair<bool,int> Document::addStringHasher(const StringHasherRef & hasher) const {
if (!hasher)
return std::make_pair(false, 0);
auto ret = d->hashers.left.insert(HasherMap::left_map::value_type(hasher,(int)d->hashers.size()));
if (ret.second)
hasher->clearMarks();
return std::make_pair(ret.second,ret.first->second);
}
StringHasherRef Document::getHasher() const {
return d->Hasher;
}
StringHasherRef Document::getStringHasher(int idx) const {
StringHasherRef hasher;
if(idx<0) {
if(UseHasher.getValue())
return d->Hasher;
return hasher;
}
auto it = d->hashers.right.find(idx);
if(it == d->hashers.right.end()) {
hasher = new StringHasher;
d->hashers.right.insert(HasherMap::right_map::value_type(idx,hasher));
}else
hasher = it->second;
return hasher;
}
struct DocExportStatus {
Document::ExportStatus status;
std::set<const App::DocumentObject*> objs;
@@ -1905,7 +1823,6 @@ Document::ExportStatus Document::isExporting(const App::DocumentObject *obj) con
void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::ostream& out) {
DocumentExporting exporting(obj);
d->hashers.clear();
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
for(auto o : obj) {
@@ -1942,7 +1859,6 @@ void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::
// write additional files
writer.writeFiles();
d->hashers.clear();
}
#define FC_ATTR_DEPENDENCIES "Dependencies"
@@ -2246,16 +2162,14 @@ Document::readObjects(Base::XMLReader& reader)
void Document::addRecomputeObject(DocumentObject *obj) {
if(testStatus(Status::Restoring) && obj) {
setStatus(Status::RecomputeOnRestore, true);
d->touchedObjs.insert(obj);
obj->enforceRecompute();
obj->touch();
}
}
std::vector<App::DocumentObject*>
Document::importObjects(Base::XMLReader& reader)
{
d->hashers.clear();
Base::FlagToggler<> flag(_IsRestoring,false);
Base::ObjectStatusLocker<Status, Document> restoreBit(Status::Restoring, this);
Base::ObjectStatusLocker<Status, Document> restoreBit2(Status::Importing, this);
@@ -2274,7 +2188,6 @@ Document::importObjects(Base::XMLReader& reader)
reader.FileVersion = 0;
}
Base::ReaderContext rctx(getName());
std::vector<App::DocumentObject*> objs = readObjects(reader);
for(auto o : objs) {
if(o && o->getNameInDocument()) {
@@ -2307,7 +2220,7 @@ Document::importObjects(Base::XMLReader& reader)
if(o && o->getNameInDocument())
o->setStatus(App::ObjImporting,false);
}
d->hashers.clear();
return objs;
}
@@ -2320,8 +2233,6 @@ unsigned int Document::getMemSize (void) const
for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it)
size += (*it)->getMemSize();
size += d->Hasher->getMemSize();
// size of the document properties...
size += PropertyContainer::getMemSize();
@@ -2491,7 +2402,7 @@ private:
fn = str.str();
}
if (!fi.renameFile(fn.c_str()))
if (fi.renameFile(fn.c_str()) == false)
Base::Console().Warning("Cannot rename project file to backup file\n");
}
else {
@@ -2500,7 +2411,7 @@ private:
}
Base::FileInfo tmp(sourcename);
if (!tmp.renameFile(targetname.c_str())) {
if (tmp.renameFile(targetname.c_str()) == false) {
throw Base::FileException(
"Cannot rename tmp save file to project file", targetname);
}
@@ -2600,7 +2511,7 @@ private:
}
}
else {
if (!renameFileNoErase(fi, fn+".FCBak")) {
if (renameFileNoErase(fi, fn+".FCBak") == false) {
fn = fn + "-";
}
else {
@@ -2644,7 +2555,7 @@ private:
}
Base::FileInfo tmp(sourcename);
if (!tmp.renameFile(targetname.c_str())) {
if (tmp.renameFile(targetname.c_str()) == false) {
throw Base::FileException(
"Save interrupted: Cannot rename temporary file to project file", tmp);
}
@@ -2703,23 +2614,30 @@ bool Document::saveToFile(const char* filename) const
bool policy = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetBool("BackupPolicy",true);
//realpath is canonical filename i.e. without symlink
#ifdef FC_OS_WIN32
QString utf8Name = QString::fromUtf8(filename);
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(utf8Name.toStdWString())));
std::string nativePath = QString::fromStdWString(realpath.native()).toStdString();
#else
auto realpath = fs::weakly_canonical(fs::absolute(fs::path(filename)));
std::string nativePath = realpath.native();
#endif
// make a tmp. file where to save the project data first and then rename to
// the actual file name. This may be useful if overwriting an existing file
// fails so that the data of the work up to now isn't lost.
std::string uuid = Base::Uuid::createUuid();
std::string fn = filename;
std::string fn = nativePath;
if (policy) {
fn += ".";
fn += uuid;
}
Base::FileInfo tmp(fn);
// In case some folders in the path do not exist
#ifdef FC_OS_WIN32
QString utf8Name = QString::fromUtf8(filename);
auto parentPath = fs::absolute(fs::path(utf8Name.toStdWString())).parent_path();
#else
auto parentPath = fs::absolute(fs::path(filename)).parent_path();
#endif
auto parentPath = realpath.parent_path();
fs::create_directories(parentPath);
// open extra scope to close ZipWriter properly
@@ -2766,9 +2684,9 @@ bool Document::saveToFile(const char* filename) const
count_bak = -1;
}
bool useFCBakExtension = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetBool("UseFCBakExtension",false);
std::string saveBackupDateFormat = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetASCII("SaveBackupDateFormat","%Y%m%d-%H%M%S");
("User parameter:BaseApp/Preferences/Document")->GetBool("UseFCBakExtension",false);
std::string saveBackupDateFormat = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetASCII("SaveBackupDateFormat","%Y%m%d-%H%M%S");
BackupPolicy policy;
if (useFCBakExtension) {
@@ -2780,7 +2698,7 @@ bool Document::saveToFile(const char* filename) const
policy.setPolicy(BackupPolicy::Standard);
}
policy.setNumberOfFiles(count_bak);
policy.apply(fn, filename);
policy.apply(fn, nativePath);
}
signalFinishSave(*this, filename);
@@ -2788,37 +2706,6 @@ bool Document::saveToFile(const char* filename) const
return true;
}
void Document::save(Base::Writer &writer, bool archive) const {
(void)archive;
writer.putNextEntry("Document.xml");
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
if (hGrp->GetBool("SaveBinaryBrep", false)) {
writer.setMode("BinaryBrep");
writer.setPreferBinary(true);
} else if(writer.getFileVersion() > 1)
writer.setPreferBinary(false);
writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>\n"
<< "<!--\n"
<< " FreeCAD Document, see http://www.freecadweb.org for more information...\n"
<< "-->\n";
Document::Save(writer);
// Special handling for Gui document.
signalSaveDocument(writer);
// write additional files
writer.writeFiles();
if (writer.hasErrors()) {
throw Base::FileException("Failed to write all data to file");
}
GetApplication().signalSaveDocument(*this);
}
bool Document::isAnyRestoring() {
return _IsRestoring;
}
@@ -2827,48 +2714,8 @@ bool Document::isAnyRestoring() {
void Document::restore (const char *filename,
bool delaySignal, const std::vector<std::string> &objNames)
{
if(!filename)
filename = FileName.getValue();
Base::FileInfo fi(filename);
if(fi.isDir()) {
fi.setFile(std::string(filename)+'/'+"Document.xml");
if(!fi.exists())
throw Base::FileException("Project file not found",fi.filePath());
}
std::unique_ptr<Base::Reader> _reader;
std::unique_ptr<Base::XMLReader> _xmlReader;
std::unique_ptr<zipios::ZipInputStream> zipstream;
std::string dirname;
if(fi.fileNamePure() == "Document" && fi.hasExtension("xml")) {
Base::FileInfo di(fi.dirPath());
_reader.reset(new Base::FileReader(fi,di.fileName()+"/Document.xml"));
_xmlReader.reset(new Base::XMLReader(*_reader));
} else {
// file.open(fi, std::ios::in | std::ios::binary);
// std::streambuf* buf = file.rdbuf();
// std::streamoff size = buf->pubseekoff(0, std::ios::end, std::ios::in);
// buf->pubseekoff(0, std::ios::beg, std::ios::in);
// if (size < 22) // an empty zip archive has 22 bytes
// throw Base::FileException("Invalid project file",filename);
zipstream.reset(new zipios::ZipInputStream(filename));
_reader.reset(new Base::ZipReader(*zipstream,filename));
_xmlReader.reset(new Base::XMLReader(*_reader));
}
restore(*_xmlReader, delaySignal, objNames);
}
void Document::restore(Base::XMLReader &reader,
bool delaySignal, const std::vector<std::string> &objNames)
{
if (!reader.isValid())
throw Base::FileException("Error reading project file", FileName.getValue());
clearUndos();
d->activeObject = nullptr;
d->files.clear();
bool signal = false;
Document *activeDoc = GetApplication().getActiveDocument();
@@ -2894,6 +2741,21 @@ void Document::restore(Base::XMLReader &reader,
GetApplication().setActiveDocument(this);
}
if(!filename)
filename = FileName.getValue();
Base::FileInfo fi(filename);
Base::ifstream file(fi, std::ios::in | std::ios::binary);
std::streambuf* buf = file.rdbuf();
std::streamoff size = buf->pubseekoff(0, std::ios::end, std::ios::in);
buf->pubseekoff(0, std::ios::beg, std::ios::in);
if (size < 22) // an empty zip archive has 22 bytes
throw Base::FileException("Invalid project file",filename);
zipios::ZipInputStream zipstream(file);
Base::XMLReader reader(filename, zipstream);
if (!reader.isValid())
throw Base::FileException("Error reading compression file",filename);
GetApplication().signalStartRestoreDocument(*this);
setStatus(Document::Restoring, true);
@@ -2903,8 +2765,6 @@ void Document::restore(Base::XMLReader &reader,
d->partialLoadObjects.emplace(name,true);
try {
Document::Restore(reader);
} catch (const Base::XMLParseException &) {
throw;
} catch (const Base::Exception& e) {
Base::Console().Error("Invalid Document.xml: %s\n", e.what());
setStatus(Document::RestoreError, true);
@@ -2918,13 +2778,7 @@ void Document::restore(Base::XMLReader &reader,
// Note: This file doesn't need to be available if the document has been created
// without GUI. But if available then follow after all data files of the App document.
signalRestoreDocument(reader);
reader.readFiles();
for(auto &f : reader.getFilenames()) {
FC_TRACE("document " << getName() << " file: " << f);
d->files.insert(f);
}
reader.readFiles(zipstream);
if (reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestore)) {
setStatus(Document::PartialRestore, true);
@@ -3072,19 +2926,10 @@ const char* Document::getName() const
return myName.c_str();
}
std::string Document::getFullName(bool python) const {
if(python) {
std::ostringstream ss;
ss << "FreeCAD.getDocument('" << myName << "')";
return ss.str();
}
std::string Document::getFullName() const {
return myName;
}
App::Document *Document::getOwnerDocument() const {
return const_cast<App::Document*>(this);
}
const char* Document::getProgramVersion() const
{
return d->programVersion.c_str();
@@ -3924,21 +3769,6 @@ const char * Document::getErrorDescription(const App::DocumentObject*Obj) const
return d->findRecomputeLog(Obj);
}
void Document::setErrorDescription(App::DocumentObject *Obj, const char *msg)
{
if (msg && msg[0] && Obj)
d->addRecomputeLog(msg, Obj);
}
void Document::setErrorDescription(App::Property *Prop, const char *msg)
{
if (msg && msg[0] && Prop) {
auto obj = Base::freecad_dynamic_cast<DocumentObject>(Prop->getContainer());
if (obj)
d->addRecomputeLog(msg, obj);
}
}
// call the recompute of the Feature and handle the exceptions and errors.
int Document::_recomputeFeature(DocumentObject* Feat)
{
+3 -60
View File
@@ -23,22 +23,13 @@
#ifndef APP_DOCUMENT_H
#define APP_DOCUMENT_H
#include <CXX/Objects.hxx>
#include <Base/Observer.h>
#include <Base/Persistence.h>
#include <Base/Type.h>
#include <Base/Handle.h>
#include "PropertyContainer.h"
#include "PropertyLinks.h"
#include "PropertyStandard.h"
#include <memory>
#include <map>
#include <vector>
class QByteArray;
namespace Base {
class Writer;
}
@@ -52,8 +43,6 @@ namespace App
class DocumentPy; // the python document class
class Application;
class Transaction;
class StringHasher;
typedef Base::Reference<StringHasher> StringHasherRef;
}
namespace App
@@ -79,7 +68,6 @@ public:
RestoreError = 10,
LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed
IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed
RecomputeOnRestore = 13, // Mark pending recompute on restore for migration purpose
};
/** @name Properties */
@@ -121,8 +109,6 @@ public:
PropertyString TipName;
/// Whether to show hidden items in TreeView
PropertyBool ShowHidden;
/// Whether to use hasher on topological naming
PropertyBool UseHasher;
//@}
/** @name Signals of the document */
@@ -200,13 +186,11 @@ public:
bool save (void);
bool saveAs(const char* file);
bool saveCopy(const char* file) const;
void save(Base::Writer &writer, bool archive) const;
/// Restore the document from the file in Property Path
void restore (const char *filename=nullptr,
bool delaySignal=false, const std::vector<std::string> &objNames={});
/// Restore the document from a pre-constructed xml reader
void restore (Base::XMLReader &xmlReader,
bool delaySignal=false, const std::vector<std::string> &objNames={});
bool afterRestore(bool checkPartial=false);
bool afterRestore(const std::vector<App::DocumentObject *> &, bool checkPartial=false);
enum ExportStatus {
NotExporting,
Exporting,
@@ -359,10 +343,6 @@ public:
bool recomputeFeature(DocumentObject* Feat,bool recursive=false);
/// get the text of the error of a specified object
const char* getErrorDescription(const App::DocumentObject*) const;
/// set the text of the error of a specified object
void setErrorDescription(App::DocumentObject *, const char *);
/// set the text of the error of a specified object
void setErrorDescription(App::Property *, const char *);
/// return the status bits
bool testStatus(Status pos) const;
/// set the status bits
@@ -487,38 +467,6 @@ public:
(const App::DocumentObject* from, const App::DocumentObject* to) const;
//@}
/** Called by property during properly save its containing StringHasher
*
* @param hasher: the input hasher
* @return Returns a pair<bool,int>. Boolean member indicate if the
* StringHasher has been saved before. The Integer is the hasher index.
*
* The StringHasher object is designed to be shared among multiple objects.
* So, we must not save duplicate copies of the same hasher. And must be
* able to restore with the same sharing relationship. This function returns
* whether the hasher has been saved before by other objects, and the index
* of the hasher. If the hasher has not been saved before, the object must
* save the hasher by calling StringHasher::Save
*/
std::pair<bool,int> addStringHasher(const StringHasherRef & hasher) const;
/** Called by property to restore its containing StringHasher
*
* @param index: the index previously returned by calling addStringHasher()
* during save. Or if is negative, then return document's own string hasher
* if UseHasher is True
*
* @return Return the resulting string hasher.
*
* The caller is responsible to restore the hasher itself if it is the first
* owner of the hasher, i.e. return addStringHasher() returns true during
* save
*/
StringHasherRef getStringHasher(int index=-1) const;
/// Return the document's own hasher regardless of UseHasher
StringHasherRef getHasher() const;
/** Return the links to a given object
*
* @param links: holds the links found
@@ -545,9 +493,7 @@ public:
virtual PyObject *getPyObject(void) override;
virtual std::string getFullName(bool python=false) const override;
virtual App::Document *getOwnerDocument() const override;
virtual std::string getFullName() const override;
/// Indicate if there is any document restoring/importing
static bool isAnyRestoring();
@@ -566,9 +512,6 @@ protected:
/// Construction
Document(const char *name = "");
bool afterRestore(bool checkPartial=false);
bool afterRestore(const std::vector<App::DocumentObject *> &, bool checkPartial=false);
void _removeObject(DocumentObject* pcObject);
void _addObject(DocumentObject* pcObject, const char* pObjectName);
/// checks if a valid transaction is open
+76 -78
View File
@@ -165,13 +165,14 @@ App::DocumentObjectExecReturn* DocumentObject::executeExtensions()
{
//execute extensions but stop on error
this->setStatus(App::RecomputeExtension, false); // reset the flag
App::DocumentObjectExecReturn *res = StdReturn;
foreachExtension<DocumentObjectExtension>([&res](DocumentObjectExtension *ext) {
res = ext->extensionExecute();
return res != StdReturn;
});
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector) {
auto ret = ext->extensionExecute();
if (ret != StdReturn)
return ret;
}
return res;
return StdReturn;
}
bool DocumentObject::recomputeFeature(bool recursive)
@@ -233,10 +234,16 @@ bool DocumentObject::mustRecompute(void) const
short DocumentObject::mustExecute(void) const
{
if (ExpressionEngine.isTouched()
|| queryExtension(&DocumentObjectExtension::extensionMustExecute))
if (ExpressionEngine.isTouched())
return 1;
//ask all extensions
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector) {
if (ext->extensionMustExecute())
return 1;
}
return 0;
}
@@ -252,24 +259,13 @@ const char* DocumentObject::getStatusString(void) const
return "Valid";
}
std::string DocumentObject::getFullName(bool python) const {
if(!getDocument() || !pcNameInDocument) {
if(python)
return std::string("None");
return std::string("?") + Base::Tools::getIdentifier(oldLabel);
}
std::ostringstream ss;
if(python) {
ss << "FreeCAD.getDocument('" << getDocument()->getName()
<< "').getObject('" << *pcNameInDocument << "')";
}else
ss << getDocument()->getName() << '#' << *pcNameInDocument;
return ss.str();
}
App::Document *DocumentObject::getOwnerDocument() const {
return _pDoc;
std::string DocumentObject::getFullName() const {
if(!getDocument() || !pcNameInDocument)
return "?";
std::string name(getDocument()->getName());
name += '#';
name += *pcNameInDocument;
return name;
}
const char *DocumentObject::getNameInDocument() const
@@ -712,13 +708,13 @@ bool DocumentObject::removeDynamicProperty(const char* name)
auto expressions = ExpressionEngine.getExpressions();
std::vector<App::ObjectIdentifier> removeExpr;
for (const auto& it : expressions) {
for (auto it : expressions) {
if (it.first.getProperty() == prop) {
removeExpr.push_back(it.first);
}
}
for (const auto& it : removeExpr) {
for (auto it : removeExpr) {
ExpressionEngine.setValue(it, std::shared_ptr<Expression>());
}
@@ -727,9 +723,9 @@ bool DocumentObject::removeDynamicProperty(const char* name)
App::Property* DocumentObject::addDynamicProperty(
const char* type, const char* name, const char* group, const char* doc,
short attr, bool readonly, bool hidden)
short attr, bool ro, bool hidden)
{
auto prop = TransactionalObject::addDynamicProperty(type,name,group,doc,attr,readonly,hidden);
auto prop = TransactionalObject::addDynamicProperty(type,name,group,doc,attr,ro,hidden);
if(prop && _pDoc)
_pDoc->addOrRemovePropertyOfObject(this, prop, true);
return prop;
@@ -748,7 +744,8 @@ void DocumentObject::onBeforeChange(const Property* prop)
signalBeforeChange(*this,*prop);
}
void DocumentObject::onEarlyChange(const Property *prop)
/// get called by the container when a Property was changed
void DocumentObject::onChanged(const Property* prop)
{
if(GetApplication().isClosingAll())
return;
@@ -766,15 +763,6 @@ void DocumentObject::onEarlyChange(const Property *prop)
}
}
signalEarlyChanged(*this, *prop);
}
/// get called by the container when a Property was changed
void DocumentObject::onChanged(const Property* prop)
{
if(GetApplication().isClosingAll())
return;
// Delay signaling view provider until the document object has handled the
// change
// if (_pDoc)
@@ -826,13 +814,14 @@ DocumentObject *DocumentObject::getSubObject(const char *subname,
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const
{
DocumentObject *ret = nullptr;
if(queryExtension(&DocumentObjectExtension::extensionGetSubObject, ret, subname, pyObj, mat, transform, depth))
return ret;
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : exts) {
if(ext->extensionGetSubObject(ret,subname,pyObj,mat,transform, depth))
return ret;
}
std::string name;
const char *dot=nullptr;
while(subname && *subname=='.')
++subname; // skip leading .
if(!subname || !(dot=strchr(subname,'.'))) {
ret = const_cast<DocumentObject*>(this);
}else if(subname[0]=='$') {
@@ -890,7 +879,11 @@ std::vector<DocumentObject*> DocumentObject::getSubObjectList(const char *subnam
std::vector<std::string> DocumentObject::getSubObjects(int reason) const {
std::vector<std::string> ret;
callExtension(&DocumentObjectExtension::extensionGetSubObjects,ret,reason);
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : exts) {
if(ext->extensionGetSubObjects(ret,reason))
return ret;
}
return ret;
}
@@ -926,8 +919,11 @@ DocumentObject *DocumentObject::getLinkedObject(
bool recursive, Base::Matrix4D *mat, bool transform, int depth) const
{
DocumentObject *ret = nullptr;
if(queryExtension(&DocumentObjectExtension::extensionGetLinkedObject, ret, recursive, mat, transform, depth))
return ret;
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : exts) {
if(ext->extensionGetLinkedObject(ret,recursive,mat,transform,depth))
return ret;
}
if(transform && mat) {
auto pla = dynamic_cast<PropertyPlacement*>(getPropertyByName("Placement"));
if(pla)
@@ -938,6 +934,8 @@ DocumentObject *DocumentObject::getLinkedObject(
void DocumentObject::Save (Base::Writer &writer) const
{
if (this->getNameInDocument())
writer.ObjectName = this->getNameInDocument();
App::ExtensionContainer::Save(writer);
}
@@ -993,7 +991,9 @@ void DocumentObject::renameObjectIdentifiers(const std::map<ObjectIdentifier, Ob
void DocumentObject::onDocumentRestored()
{
//call all extensions
callExtension(&DocumentObjectExtension::onExtendedDocumentRestored);
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector)
ext->onExtendedDocumentRestored();
if(Visibility.testStatus(Property::Output))
Visibility.setStatus(Property::NoModify,true);
}
@@ -1006,19 +1006,25 @@ void DocumentObject::onUndoRedoFinished()
void DocumentObject::onSettingDocument()
{
//call all extensions
callExtension(&DocumentObjectExtension::onExtendedSettingDocument);
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector)
ext->onExtendedSettingDocument();
}
void DocumentObject::setupObject()
{
//call all extensions
callExtension(&DocumentObjectExtension::onExtendedSetupObject);
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector)
ext->onExtendedSetupObject();
}
void DocumentObject::unsetupObject()
{
//call all extensions
callExtension(&DocumentObjectExtension::onExtendedUnsetupObject);
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
for(auto ext : vector)
ext->onExtendedUnsetupObject();
}
void App::DocumentObject::_removeBackLink(DocumentObject* rmvObj)
@@ -1048,25 +1054,31 @@ void App::DocumentObject::_addBackLink(DocumentObject* newObj)
}
int DocumentObject::setElementVisible(const char *element, bool visible) {
int res = -1;
foreachExtension<DocumentObjectExtension>([&res,element,visible](DocumentObjectExtension *ext) {
res = ext->extensionSetElementVisible(element,visible);
return res>=0;
});
return res;
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
int ret = ext->extensionSetElementVisible(element,visible);
if(ret>=0)
return ret;
}
return -1;
}
int DocumentObject::isElementVisible(const char *element) const {
int res = -1;
foreachExtension<DocumentObjectExtension>([&res,element](DocumentObjectExtension *ext) {
res = ext->extensionIsElementVisible(element);
return res>=0;
});
return res;
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
int ret = ext->extensionIsElementVisible(element);
if(ret>=0)
return ret;
}
return -1;
}
bool DocumentObject::hasChildElement() const {
return queryExtension(&DocumentObjectExtension::extensionHasChildElement);
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
if(ext->extensionHasChildElement())
return true;
}
return false;
}
DocumentObject *DocumentObject::resolve(const char *subname,
@@ -1241,20 +1253,6 @@ bool DocumentObject::adjustRelativeLinks(
return touched;
}
std::string DocumentObject::getElementMapVersion(const App::Property *_prop, bool restored) const {
auto prop = Base::freecad_dynamic_cast<const PropertyComplexGeoData>(_prop);
if(!prop)
return std::string();
return prop->getElementMapVersion(restored);
}
bool DocumentObject::checkElementMapVersion(const App::Property *_prop, const char *ver) const {
auto prop = Base::freecad_dynamic_cast<const PropertyComplexGeoData>(_prop);
if(!prop)
return false;
return prop->checkElementMapVersion(ver);
}
const std::string &DocumentObject::hiddenMarker() {
static std::string marker("!hide");
return marker;
+23 -41
View File
@@ -66,6 +66,7 @@ enum ObjectStatus {
NoAutoExpand = 17, // disable tree item auto expand on selection for this object
PendingTransactionUpdate = 18, // mark that the object expects a call to onUndoRedoFinished() after transaction is finished.
RecomputeExtension = 19, // mark the object to recompute its extensions
TouchOnColorChange = 20, // inform view provider touch object on color change
};
/** Return object for feature execution
@@ -109,11 +110,9 @@ public:
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChange;
/// signal on changed property of this object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChanged;
/// signal on changed property of this object before document scoped signalChangedObject
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalEarlyChanged;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
virtual const char* getViewProviderName() const {
return "";
}
/**
@@ -130,22 +129,21 @@ public:
}
/// Constructor
DocumentObject(void);
DocumentObject();
virtual ~DocumentObject();
/// returns the name which is set in the document for this object (not the name property!)
const char *getNameInDocument(void) const;
const char *getNameInDocument() const;
/// Return the object ID that is unique within its owner document
long getID() const {return _Id;}
/// returns the name that is safe to be exported to other document
std::string getExportName(bool forced=false) const;
/// Return the object full name of the form DocName#ObjName
virtual std::string getFullName(bool python=false) const override;
virtual App::Document *getOwnerDocument() const override;
virtual std::string getFullName() const override;
virtual bool isAttachedToDocument() const override;
virtual const char* detachFromDocument() override;
/// gets the document in which this Object is handled
App::Document *getDocument(void) const;
App::Document *getDocument() const;
/** Set the property touched -> changed, cause recomputation in Update()
*/
@@ -153,22 +151,22 @@ public:
/// set this document object touched (cause recomputation on dependent features)
void touch(bool noRecompute=false);
/// test if this document object is touched
bool isTouched(void) const;
bool isTouched() const;
/// Enforce this document object to be recomputed
void enforceRecompute();
/// Test if this document object must be recomputed
bool mustRecompute(void) const;
bool mustRecompute() const;
/// reset this document object touched
void purgeTouched(void) {
void purgeTouched() {
StatusBits.reset(ObjectStatus::Touch);
StatusBits.reset(ObjectStatus::Enforce);
setPropertyStatus(0,false);
}
/// set this feature to error
bool isError(void) const {return StatusBits.test(ObjectStatus::Error);}
bool isValid(void) const {return !StatusBits.test(ObjectStatus::Error);}
bool isError() const {return StatusBits.test(ObjectStatus::Error);}
bool isValid() const {return !StatusBits.test(ObjectStatus::Error);}
/// remove the error from the object
void purgeError(void){StatusBits.reset(ObjectStatus::Error);}
void purgeError(){StatusBits.reset(ObjectStatus::Error);}
/// returns true if this objects is currently recomputing
bool isRecomputing() const {return StatusBits.test(ObjectStatus::Recompute);}
/// returns true if this objects is currently restoring from file
@@ -230,7 +228,7 @@ public:
/// returns a list of objects linked by the property
std::vector<App::DocumentObject*> getOutListOfProperty(App::Property*) const;
/// returns a list of objects this object is pointing to by Links and all further descended
std::vector<App::DocumentObject*> getOutListRecursive(void) const;
std::vector<App::DocumentObject*> getOutListRecursive() const;
/// clear internal out list cache
void clearOutListCache() const;
/// get all possible paths from this to another object following the OutList
@@ -239,10 +237,10 @@ public:
/// get all objects link to this object
std::vector<App::DocumentObject*> getInList(void) const
#else
const std::vector<App::DocumentObject*> &getInList(void) const;
const std::vector<App::DocumentObject*> &getInList() const;
#endif
/// get all objects link directly or indirectly to this object
std::vector<App::DocumentObject*> getInListRecursive(void) const;
std::vector<App::DocumentObject*> getInListRecursive() const;
/** Get a set of all objects linking to this object, including possible external parent objects
*
* @param inSet [out]: a set containing all objects linking to this object.
@@ -289,20 +287,6 @@ public:
bool testIfLinkDAGCompatible(App::PropertyLinkSubList &linksTo) const;
bool testIfLinkDAGCompatible(App::PropertyLinkSub &linkTo) const;
/** Return the element map version of the geometry data stored in the given property
*
* @param prop: the geometry property to query for element map version
* @param restored: whether to query for the restored element map version.
* In case of version upgrade, the restored version may
* be different from the current version.
*
* @return Return the element map version string.
*/
virtual std::string getElementMapVersion(const App::Property *prop, bool restored=false) const;
/// Return true to signal re-generation of geometry element names
virtual bool checkElementMapVersion(const App::Property *prop, const char *ver) const;
public:
/** mustExecute
* We call this method to check if the object was modified to
@@ -315,7 +299,7 @@ public:
* necessarily mean that it will be recomputed. It only means that all
* objects that link it (i.e. its InList) will be recomputed.
*/
virtual short mustExecute(void) const;
virtual short mustExecute() const;
/** Recompute only this feature
*
@@ -324,7 +308,7 @@ public:
bool recomputeFeature(bool recursive=false);
/// get the status Message
const char *getStatusString(void) const;
const char *getStatusString() const;
/** Called in case of losing a link
* Get called by the document when a object got deleted a link property of this
@@ -333,7 +317,7 @@ public:
* additional or different behavior.
*/
virtual void onLostLinkToObject(DocumentObject*);
virtual PyObject *getPyObject(void) override;
virtual PyObject *getPyObject() override;
/** Get the sub element/object by name
*
@@ -458,7 +442,7 @@ public:
virtual App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool readonly=false, bool hidden=false) override;
short attr=0, bool ro=false, bool hidden=false) override;
/** Resolve the last document object referenced in the subname
*
@@ -577,7 +561,7 @@ public:
protected:
/// recompute only this object
virtual App::DocumentObjectExecReturn *recompute(void);
virtual App::DocumentObjectExecReturn *recompute();
/** get called by the document to recompute this feature
* Normally this method get called in the processing of
* Document::recompute().
@@ -585,7 +569,7 @@ protected:
* with the data from linked objects and objects own
* properties.
*/
virtual App::DocumentObjectExecReturn *execute(void);
virtual App::DocumentObjectExecReturn *execute();
/**
* Executes the extensions of a document object.
@@ -608,16 +592,14 @@ protected:
*/
std::bitset<32> StatusBits;
void setError(void){StatusBits.set(ObjectStatus::Error);}
void resetError(void){StatusBits.reset(ObjectStatus::Error);}
void setError(){StatusBits.set(ObjectStatus::Error);}
void resetError(){StatusBits.reset(ObjectStatus::Error);}
void setDocument(App::Document* doc);
/// get called before the value is changed
virtual void onBeforeChange(const Property* prop) override;
/// get called by the container when a property was changed
virtual void onChanged(const Property* prop) override;
/// get called by the container when a property was changed
virtual void onEarlyChange(const Property* prop) override;
/// get called after a document has been fully restored
virtual void onDocumentRestored();
/// get called after an undo/redo transaction is finished
+1 -1
View File
@@ -96,7 +96,7 @@ public:
Base::Matrix4D *mat, bool transform, int depth) const;
virtual int extensionSetElementVisible(const char *, bool) {return -1;}
virtual int extensionIsElementVisible(const char *) const {return -1;}
virtual int extensionIsElementVisible(const char *) {return -1;}
virtual bool extensionHasChildElement() const {return false;}
};
+14 -14
View File
@@ -374,12 +374,12 @@ PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
PyObject* DocumentObjectPy::recompute(PyObject *args)
{
PyObject *recursive = Py_False;
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive))
PyObject *recursive=Py_False;
if (!PyArg_ParseTuple(args, "|O",&recursive))
return nullptr;
try {
bool ok = getDocumentObjectPtr()->recomputeFeature(PyObject_IsTrue(recursive) ? true : false);
bool ok = getDocumentObjectPtr()->recomputeFeature(PyObject_IsTrue(recursive));
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
catch (const Base::Exception& e) {
@@ -434,8 +434,8 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
short depth = 0;
static char *kwlist[] = {"subname", "retType", "matrix", "transform", "depth", nullptr};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hO!O!h", kwlist,
&obj, &retType, &Base::MatrixPy::Type, &pyMat, &PyBool_Type, &doTransform, &depth))
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hO!Oh", kwlist,
&obj, &retType, &Base::MatrixPy::Type, &pyMat, &doTransform, &depth))
return nullptr;
if (retType < 0 || retType > 6) {
@@ -469,7 +469,7 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
return nullptr;
}
bool transform = PyObject_IsTrue(doTransform) ? true : false;
bool transform = PyObject_IsTrue(doTransform);
struct SubInfo {
App::DocumentObject *sobj;
@@ -578,8 +578,8 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
PyObject *transform = Py_True;
short depth = 0;
static char *kwlist[] = {"recursive","matrix","transform","depth", nullptr};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O!OO!h", kwlist,
&PyBool_Type,&recursive,&pyMat,&PyBool_Type,&transform,&depth))
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|OOOh", kwlist,
&recursive,&pyMat,&transform,&depth))
return nullptr;
Base::Matrix4D _mat;
@@ -595,7 +595,7 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
PY_TRY {
auto linked = getDocumentObjectPtr()->getLinkedObject(
PyObject_IsTrue(recursive) ? true : false, mat, PyObject_IsTrue(transform) ? true : false, depth);
PyObject_IsTrue(recursive), mat, PyObject_IsTrue(transform),depth);
if(!linked)
linked = getDocumentObjectPtr();
auto pyObj = Py::Object(linked->getPyObject(),true);
@@ -623,10 +623,10 @@ PyObject* DocumentObjectPy::setElementVisible(PyObject *args)
{
char *element = nullptr;
PyObject *visible = Py_True;
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible))
if (!PyArg_ParseTuple(args, "s|O", &element,&visible))
return nullptr;
PY_TRY {
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element,PyObject_IsTrue(visible) ? true : false));
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element,PyObject_IsTrue(visible)));
} PY_CATCH;
}
@@ -830,13 +830,13 @@ PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
const char *subname;
PyObject *append = Py_False;
int type = 0;
if (!PyArg_ParseTuple(args, "s|O!i",&subname,&PyBool_Type,&append,&type))
if (!PyArg_ParseTuple(args, "s|Oi",&subname,&append,&type))
return nullptr;
PY_TRY {
std::pair<std::string,std::string> elementName;
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
PyObject_IsTrue(append) ? true : false,(GeoFeature::ElementNameType)type);
PyObject_IsTrue(append),(GeoFeature::ElementNameType)type);
Py::Tuple ret(3);
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
ret.setItem(1,Py::String(elementName.first));
@@ -866,7 +866,7 @@ PyObject *DocumentObjectPy::adjustRelativeLinks(PyObject *args) {
std::set<App::DocumentObject *> visited;
return Py::new_reference_to(Py::Boolean(
getDocumentObjectPtr()->adjustRelativeLinks(inList,
PyObject_IsTrue(recursive) ? &visited : nullptr)));
PyObject_IsTrue(recursive)?&visited:nullptr)));
}PY_CATCH
}
+24 -207
View File
@@ -24,12 +24,10 @@
#include "PreCompiled.h"
#include <Base/Tools.h>
#include <Base/Interpreter.h>
#include <App/DocumentObjectPy.h>
#include "Application.h"
#include "ComplexGeoData.h"
#include "Document.h"
#include "DocumentObject.h"
#include "DocumentObserver.h"
#include "GeoFeature.h"
@@ -201,18 +199,6 @@ bool DocumentObjectT::operator==(const DocumentObjectT &other) const {
&& property == other.property;
}
bool DocumentObjectT::operator<(const DocumentObjectT &other) const {
if(getDocumentName() < other.getDocumentName())
return true;
if(getDocumentName() > other.getDocumentName())
return false;
if(getObjectName() < other.getObjectName())
return true;
if(getObjectName() > other.getObjectName())
return false;
return getPropertyName() < other.getPropertyName();
}
Document* DocumentObjectT::getDocument() const
{
return GetApplication().getDocument(document.c_str());
@@ -312,44 +298,6 @@ SubObjectT::SubObjectT(const char *docName, const char *objName, const char *s)
{
}
SubObjectT::SubObjectT(const std::vector<App::DocumentObject*> &objs, const char *s)
{
if (objs.empty())
return;
static_cast<DocumentObjectT&>(*this) = objs.front();
std::ostringstream ss;
for (auto it = objs.begin()+1; it!=objs.end(); ++it) {
auto obj = *it;
if (!obj || !obj->getNameInDocument())
continue;
ss << obj->getNameInDocument() << ".";
}
if (s)
ss << s;
subname = ss.str();
}
SubObjectT::SubObjectT(std::vector<App::DocumentObject*>::const_iterator begin,
std::vector<App::DocumentObject*>::const_iterator end,
const char *s)
{
if (begin == end)
return;
static_cast<DocumentObjectT&>(*this) = *begin;
std::ostringstream ss;
for (auto it = begin+1; it != end; ++it) {
auto obj = *it;
if (!obj || !obj->getNameInDocument())
continue;
ss << obj->getNameInDocument() << ".";
}
if (s)
ss << s;
subname = ss.str();
}
bool SubObjectT::operator<(const SubObjectT &other) const {
if(getDocumentName() < other.getDocumentName())
return true;
@@ -409,107 +357,45 @@ void SubObjectT::setSubName(const char *s) {
subname = s?s:"";
}
bool SubObjectT::normalize()
{
std::ostringstream ss;
auto objs = getSubObjectList();
for (unsigned i=1; i<objs.size(); ++i)
ss << objs[i]->getNameInDocument() << ".";
if (objs.front()->getSubObject(ss.str().c_str()) != objs.back()) {
// something went wrong
return false;
}
ss << getOldElementName();
std::string sub = ss.str();
if (subname != sub) {
subname = std::move(sub);
return true;
}
return false;
}
SubObjectT App::SubObjectT::normalized() const
{
SubObjectT res(*this);
res.normalize();
return res;
}
const std::string &SubObjectT::getSubName() const {
return subname;
}
std::string SubObjectT::getSubNameNoElement(bool withObjName) const {
if (!withObjName)
return Data::ComplexGeoData::noElementName(subname.c_str());
std::string res(getObjectName());
res += ".";
const char * element = Data::ComplexGeoData::findElementName(subname.c_str());
if(element)
return res.insert(res.size(), subname.c_str(), element - subname.c_str());
return res;
std::string SubObjectT::getSubNameNoElement() const {
return Data::ComplexGeoData::noElementName(subname.c_str());
}
const char *SubObjectT::getElementName() const {
return Data::ComplexGeoData::findElementName(subname.c_str());
}
bool SubObjectT::hasSubObject() const {
return Data::ComplexGeoData::findElementName(subname.c_str()) != subname.c_str();
}
bool SubObjectT::hasSubElement() const {
auto element = getElementName();
return element && element[0];
}
std::string SubObjectT::getNewElementName(bool fallback) const {
const char *elementName = Data::ComplexGeoData::findElementName(subname.c_str());
if (!elementName || !elementName[0])
return std::string();
std::string name = Data::ComplexGeoData::newElementName(elementName);
if (name.size())
return name;
std::string SubObjectT::getNewElementName() const {
std::pair<std::string, std::string> element;
auto obj = getObject();
if(!obj)
return std::string();
GeoFeature::resolveElement(obj,subname.c_str(),element);
if (!element.first.empty() || !fallback)
return std::move(element.first);
return std::move(element.first);
}
std::string SubObjectT::getOldElementName(int *index) const {
std::pair<std::string, std::string> element;
auto obj = getObject();
if(!obj)
return std::string();
GeoFeature::resolveElement(obj,subname.c_str(),element);
if(!index)
return std::move(element.second);
std::size_t pos = element.second.find_first_of("0123456789");
if(pos == std::string::npos)
*index = -1;
else {
*index = std::atoi(element.second.c_str()+pos);
element.second.resize(pos);
}
return std::move(element.second);
}
std::string SubObjectT::getOldElementName(int *index, bool fallback) const {
const char *elementName = Data::ComplexGeoData::findElementName(subname.c_str());
if (!elementName || !elementName[0])
return std::string();
std::string name = Data::ComplexGeoData::oldElementName(elementName);
if (name.empty()) {
std::pair<std::string, std::string> element;
auto obj = getObject();
if(!obj)
return std::string();
GeoFeature::resolveElement(obj,subname.c_str(),element);
if (!element.second.empty())
name = std::move(element.second);
else if (fallback && !element.first.empty())
name = std::move(element.first);
else
return std::string();
}
if(index) {
std::size_t pos = name.find_first_of("0123456789");
if(pos == std::string::npos)
*index = -1;
else {
*index = std::atoi(name.c_str()+pos);
name.resize(pos);
}
}
return name;
}
App::DocumentObject *SubObjectT::getSubObject() const {
auto obj = getObject();
if(obj)
@@ -521,8 +407,8 @@ std::string SubObjectT::getSubObjectPython(bool force) const {
if(!force && subname.empty())
return getObjectPython();
std::stringstream str;
str << "(" << getObjectPython() << ", '"
<< Base::Tools::escapeEncodeString(normalized().subname) << "')";
str << "(" << getObjectPython() << ",u'"
<< Base::Tools::escapedUnicodeFromUtf8(subname.c_str()) << "')";
return str.str();
}
@@ -533,38 +419,6 @@ std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const {
return {};
}
SubObjectT SubObjectT::getParent() const {
const char *pos = Data::ComplexGeoData::findElementName(subname.c_str());
if (!pos || pos == subname.c_str())
return SubObjectT();
if(*pos != '.')
--pos;
if(--pos <= subname.c_str())
return SubObjectT();
bool found = false;
for(;pos!=subname.c_str();--pos) {
if(*pos != '.') {
found = true;
continue;
}
if(found)
return SubObjectT(getDocumentName().c_str(),
getObjectName().c_str(), std::string(subname.c_str(), pos+1).c_str());
}
return SubObjectT(getDocumentName().c_str(), getObjectName().c_str(), nullptr);
}
SubObjectT SubObjectT::getChild(const App::DocumentObject *child) const
{
if (getObjectName().empty())
return SubObjectT(child);
SubObjectT res = *this;
res.setSubName(getSubNameNoElement() + child->getNameInDocument() + ".");
return res;
}
std::string SubObjectT::getObjectFullName(const char *docName) const
{
std::ostringstream ss;
@@ -602,43 +456,6 @@ std::string SubObjectT::getSubObjectFullName(const char *docName) const
return ss.str();
}
PyObject *SubObjectT::getPyObject() const
{
auto obj = getObject();
if (!obj)
return Py::new_reference_to(Py::Object());
if (subname.empty())
return obj->getPyObject();
return Py::new_reference_to(Py::TupleN(
Py::asObject(obj->getPyObject()), Py::String(subname)));
}
void SubObjectT::setPyObject(PyObject *pyobj)
{
try {
if (!pyobj)
throw Base::ValueError("Invalid object");
if (PyObject_TypeCheck(pyobj, &App::DocumentObjectPy::Type)) {
this->operator=(static_cast<App::DocumentObjectPy*>(pyobj)->getDocumentObjectPtr());
return;
} else if (PySequence_Check(pyobj) && PySequence_Size(pyobj)==2) {
Py::Sequence seq(pyobj);
App::DocumentObject *obj;
PropertyString tmp;
if (PyObject_TypeCheck(seq[0].ptr(), &App::DocumentObjectPy::Type)) {
obj = static_cast<App::DocumentObjectPy*>(seq[0].ptr())->getDocumentObjectPtr();
tmp.setPyObject(seq[1].ptr());
this->operator=(App::SubObjectT(obj, tmp.getValue()));
return;
}
}
} catch (Py::Exception &) {
Base::PyException e;
} catch (...) {
}
throw Base::ValueError("Expect either document object or tuple(obj, subname)");
}
// -----------------------------------------------------------------------------
PropertyLinkT::PropertyLinkT()
+4 -48
View File
@@ -118,8 +118,6 @@ public:
void operator=(const Property*);
/*! Equality operator */
bool operator==(const DocumentObjectT&) const;
/*! Less than operator */
bool operator<(const DocumentObjectT &other) const;
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
Document* getDocument() const;
@@ -184,14 +182,6 @@ public:
/*! Constructor */
SubObjectT(const char *docName, const char *objName, const char *subname);
/*! Constructor */
SubObjectT(const std::vector<App::DocumentObject*> & objs, const char *subname = nullptr);
/*! Constructor */
SubObjectT(std::vector<App::DocumentObject*>::const_iterator begin,
std::vector<App::DocumentObject*>::const_iterator end,
const char *subname = nullptr);
/*! Assignment operator */
SubObjectT &operator=(const SubObjectT&);
@@ -229,32 +219,19 @@ public:
* if it is different then the given 'doc'.
*/
std::string getSubObjectFullName(const char *docName=nullptr) const;
/// Return the subname path without sub-element
std::string getSubNameNoElement(bool withObjName=false) const;
std::string getSubNameNoElement() const;
/// Return the sub-element (Face, Edge, etc) of the subname path
const char *getElementName() const;
/// Check if there is any sub object reference
bool hasSubObject() const;
/// Check if there is any sub element reference
bool hasSubElement() const;
/** Return the new style sub-element name
*
* @param fallback: if true, then fallback to old style element name if
* there is no new style name.
*/
std::string getNewElementName(bool fallback=true) const;
/// Return the new style sub-element name
std::string getNewElementName() const;
/** Return the old style sub-element name
* @param index: if given, then return the element type, and extract the index
* @param fallback: if true, then fallback to new style element name if
* there is no old style name.
*/
std::string getOldElementName(int *index=nullptr, bool fallback=true) const;
std::string getOldElementName(int *index=nullptr) const;
/// Return the sub-object
DocumentObject *getSubObject() const;
@@ -264,29 +241,8 @@ public:
bool operator<(const SubObjectT &other) const;
/** Obtain a string to access the sub object using DocumentObject.getSubObject() API
*
* @param force: whether to call getSubObject() even if there is no subname
*/
std::string getSubObjectPython(bool force=true) const;
/** Normalize the subname path to use only the object internal name and old style element name
* @return Return whether the subname has been changed
*/
bool normalize();
/// Return a normalize copy of itself
SubObjectT normalized() const;
/// Return the parent object
SubObjectT getParent() const;
/// Return the child object
SubObjectT getChild(const App::DocumentObject *) const;
PyObject *getPyObject() const;
void setPyObject(PyObject *);
private:
std::string subname;
};
File diff suppressed because it is too large Load Diff
-359
View File
@@ -1,359 +0,0 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 DOCUMENT_PARAMS_H
#define DOCUMENT_PARAMS_H
/*[[[cog
import DocumentParams
DocumentParams.declare()
]]]*/
// Auto generated code (Tools/params_utils.py:68)
#include <Base/Parameter.h>
#include <boost_signals2.hpp>
// Auto generated code (Tools/params_utils.py:74)
namespace App {
/** Convenient class to obtain App::Document related parameters
* The parameters are under group "User parameter:BaseApp/Preferences/Document"
*
* This class is auto generated by App/DocumentParams.py. Modify that file
* instead of this one, if you want to add any parameter. You need
* to install Cog Python package for code generation:
* @code
* pip install cogapp
* @endcode
*
* Once modified, you can regenerate the header and the source file,
* @code
* python3 -m cogapp -r App/DocumentParams.h App/DocumentParams.cpp
* @endcode
*
* You can add a new parameter by adding lines in App/DocumentParams.py. Available
* parameter types are 'Int, UInt, String, Bool, Float'. For example, to add
* a new Int type parameter,
* @code
* ParamInt(parameter_name, default_value, documentation, on_change=False)
* @endcode
*
* If there is special handling on parameter change, pass in on_change=True.
* And you need to provide a function implementation in App/DocumentParams.cpp with
* the following signature.
* @code
* void DocumentParams:on<parameter_name>Changed()
* @endcode
*/
class AppExport DocumentParams {
public:
static ParameterGrp::handle getHandle();
static boost::signals2::signal<void (const char*)> &signalParamChanged();
static void signalAll();
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter prefAuthor
static const std::string & getprefAuthor();
static const std::string & defaultprefAuthor();
static void removeprefAuthor();
static void setprefAuthor(const std::string &v);
static const char *docprefAuthor();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter prefSetAuthorOnSave
static const bool & getprefSetAuthorOnSave();
static const bool & defaultprefSetAuthorOnSave();
static void removeprefSetAuthorOnSave();
static void setprefSetAuthorOnSave(const bool &v);
static const char *docprefSetAuthorOnSave();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter prefCompany
static const std::string & getprefCompany();
static const std::string & defaultprefCompany();
static void removeprefCompany();
static void setprefCompany(const std::string &v);
static const char *docprefCompany();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter prefLicenseType
static const long & getprefLicenseType();
static const long & defaultprefLicenseType();
static void removeprefLicenseType();
static void setprefLicenseType(const long &v);
static const char *docprefLicenseType();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter prefLicenseUrl
static const std::string & getprefLicenseUrl();
static const std::string & defaultprefLicenseUrl();
static void removeprefLicenseUrl();
static void setprefLicenseUrl(const std::string &v);
static const char *docprefLicenseUrl();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter CompressionLevel
static const long & getCompressionLevel();
static const long & defaultCompressionLevel();
static void removeCompressionLevel();
static void setCompressionLevel(const long &v);
static const char *docCompressionLevel();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter CheckExtension
static const bool & getCheckExtension();
static const bool & defaultCheckExtension();
static void removeCheckExtension();
static void setCheckExtension(const bool &v);
static const char *docCheckExtension();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter ForceXML
static const long & getForceXML();
static const long & defaultForceXML();
static void removeForceXML();
static void setForceXML(const long &v);
static const char *docForceXML();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter SplitXML
static const bool & getSplitXML();
static const bool & defaultSplitXML();
static void removeSplitXML();
static void setSplitXML(const bool &v);
static const char *docSplitXML();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter PreferBinary
static const bool & getPreferBinary();
static const bool & defaultPreferBinary();
static void removePreferBinary();
static void setPreferBinary(const bool &v);
static const char *docPreferBinary();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter AutoRemoveFile
static const bool & getAutoRemoveFile();
static const bool & defaultAutoRemoveFile();
static void removeAutoRemoveFile();
static void setAutoRemoveFile(const bool &v);
static const char *docAutoRemoveFile();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter BackupPolicy
static const bool & getBackupPolicy();
static const bool & defaultBackupPolicy();
static void removeBackupPolicy();
static void setBackupPolicy(const bool &v);
static const char *docBackupPolicy();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter CreateBackupFiles
static const bool & getCreateBackupFiles();
static const bool & defaultCreateBackupFiles();
static void removeCreateBackupFiles();
static void setCreateBackupFiles(const bool &v);
static const char *docCreateBackupFiles();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter UseFCBakExtension
static const bool & getUseFCBakExtension();
static const bool & defaultUseFCBakExtension();
static void removeUseFCBakExtension();
static void setUseFCBakExtension(const bool &v);
static const char *docUseFCBakExtension();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter SaveBackupDateFormat
static const std::string & getSaveBackupDateFormat();
static const std::string & defaultSaveBackupDateFormat();
static void removeSaveBackupDateFormat();
static void setSaveBackupDateFormat(const std::string &v);
static const char *docSaveBackupDateFormat();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter CountBackupFiles
static const long & getCountBackupFiles();
static const long & defaultCountBackupFiles();
static void removeCountBackupFiles();
static void setCountBackupFiles(const long &v);
static const char *docCountBackupFiles();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter OptimizeRecompute
static const bool & getOptimizeRecompute();
static const bool & defaultOptimizeRecompute();
static void removeOptimizeRecompute();
static void setOptimizeRecompute(const bool &v);
static const char *docOptimizeRecompute();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter CanAbortRecompute
static const bool & getCanAbortRecompute();
static const bool & defaultCanAbortRecompute();
static void removeCanAbortRecompute();
static void setCanAbortRecompute(const bool &v);
static const char *docCanAbortRecompute();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter UseHasher
static const bool & getUseHasher();
static const bool & defaultUseHasher();
static void removeUseHasher();
static void setUseHasher(const bool &v);
static const char *docUseHasher();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter ViewObjectTransaction
static const bool & getViewObjectTransaction();
static const bool & defaultViewObjectTransaction();
static void removeViewObjectTransaction();
static void setViewObjectTransaction(const bool &v);
static const char *docViewObjectTransaction();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter WarnRecomputeOnRestore
static const bool & getWarnRecomputeOnRestore();
static const bool & defaultWarnRecomputeOnRestore();
static void removeWarnRecomputeOnRestore();
static void setWarnRecomputeOnRestore(const bool &v);
static const char *docWarnRecomputeOnRestore();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter NoPartialLoading
static const bool & getNoPartialLoading();
static const bool & defaultNoPartialLoading();
static void removeNoPartialLoading();
static void setNoPartialLoading(const bool &v);
static const char *docNoPartialLoading();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter ThumbnailNoBackground
static const bool & getThumbnailNoBackground();
static const bool & defaultThumbnailNoBackground();
static void removeThumbnailNoBackground();
static void setThumbnailNoBackground(const bool &v);
static const char *docThumbnailNoBackground();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter ThumbnailSampleSize
static const long & getThumbnailSampleSize();
static const long & defaultThumbnailSampleSize();
static void removeThumbnailSampleSize();
static void setThumbnailSampleSize(const long &v);
static const char *docThumbnailSampleSize();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter DuplicateLabels
static const bool & getDuplicateLabels();
static const bool & defaultDuplicateLabels();
static void removeDuplicateLabels();
static void setDuplicateLabels(const bool &v);
static const char *docDuplicateLabels();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter TransactionOnRecompute
static const bool & getTransactionOnRecompute();
static const bool & defaultTransactionOnRecompute();
static void removeTransactionOnRecompute();
static void setTransactionOnRecompute(const bool &v);
static const char *docTransactionOnRecompute();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter RelativeStringID
static const bool & getRelativeStringID();
static const bool & defaultRelativeStringID();
static void removeRelativeStringID();
static void setRelativeStringID(const bool &v);
static const char *docRelativeStringID();
//@}
// Auto generated code (Tools/params_utils.py:118)
//@{
/// Accessor for parameter EnableMaterialEdit
static const bool & getEnableMaterialEdit();
static const bool & defaultEnableMaterialEdit();
static void removeEnableMaterialEdit();
static void setEnableMaterialEdit(const bool &v);
static const char *docEnableMaterialEdit();
//@}
// Auto generated code (Tools/params_utils.py:146)
}; // class DocumentParams
} // namespace App
//[[[end]]]
#endif // DOCUMENT_PARAMS_H
+10 -10
View File
@@ -212,13 +212,13 @@ PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
PyObject* view=nullptr;
PyObject *attach=Py_False;
static char *kwlist[] = {"type","name","objProxy","viewProxy","attach","viewType",nullptr};
if (!PyArg_ParseTupleAndKeywords(args,kwd,"s|sOOO!s",
kwlist, &sType,&sName,&obj,&view,&PyBool_Type,&attach,&sViewType))
if (!PyArg_ParseTupleAndKeywords(args,kwd,"s|sOOOs",
kwlist, &sType,&sName,&obj,&view,&attach,&sViewType))
return nullptr;
DocumentObject *pcFtr = nullptr;
if (!obj || (PyObject_IsTrue(attach) ? false : true)) {
if (!obj || !PyObject_IsTrue(attach)) {
pcFtr = getDocumentPtr()->addObject(sType,sName,true,sViewType);
}
else {
@@ -248,7 +248,7 @@ PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
}
pyftr.setAttr("Proxy", pyobj);
if (PyObject_IsTrue(attach) ? true : false) {
if (PyObject_IsTrue(attach)) {
getDocumentPtr()->addObject(pcFtr,sName);
try {
@@ -307,7 +307,7 @@ PyObject* DocumentPy::removeObject(PyObject *args)
PyObject* DocumentPy::copyObject(PyObject *args)
{
PyObject *obj, *rec=Py_False, *retAll=Py_False;
if (!PyArg_ParseTuple(args, "O|O!O!",&obj,&PyBool_Type,&rec,&PyBool_Type,&retAll))
if (!PyArg_ParseTuple(args, "O|OO",&obj,&rec,&retAll))
return nullptr;
std::vector<App::DocumentObject*> objs;
@@ -333,7 +333,7 @@ PyObject* DocumentPy::copyObject(PyObject *args)
}
PY_TRY {
auto ret = getDocumentPtr()->copyObject(objs, PyObject_IsTrue(rec) ? true : false, PyObject_IsTrue(retAll) ? true : false);
auto ret = getDocumentPtr()->copyObject(objs, PyObject_IsTrue(rec), PyObject_IsTrue(retAll));
if (ret.size()==1 && single)
return ret[0]->getPyObject();
@@ -525,10 +525,10 @@ PyObject* DocumentPy::recompute(PyObject * args)
}
int options = 0;
if (PyObject_IsTrue(checkCycle) ? true : false)
if (PyObject_IsTrue(checkCycle))
options = Document::DepNoCycle;
int objectCount = getDocumentPtr()->recompute(objs, PyObject_IsTrue(force) ? true : false, nullptr, options);
int objectCount = getDocumentPtr()->recompute(objs, PyObject_IsTrue(force), nullptr, options);
// Document::recompute() hides possibly raised Python exceptions by its features
// So, check if an error is set and return null if yes
@@ -901,10 +901,10 @@ Py::List DocumentPy::getOutList(void) const
PyObject *DocumentPy::getDependentDocuments(PyObject *args) {
PyObject *sort = Py_True;
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
if (!PyArg_ParseTuple(args, "|O", &sort))
return nullptr;
PY_TRY {
auto docs = getDocumentPtr()->getDependentDocuments(PyObject_IsTrue(sort) ? true : false);
auto docs = getDocumentPtr()->getDependentDocuments(PyObject_IsTrue(sort));
Py::List ret;
for (auto doc : docs)
ret.append(Py::Object(doc->getPyObject(), true));
+179 -113
View File
@@ -28,81 +28,76 @@
#include <Base/Exception.h>
#include "Enumeration.h"
#include <string_view>
using namespace App;
namespace {
struct StringCopy : public Enumeration::Object {
StringCopy(const char* str) : d(str) {
}
const char* data() const {
return d.data();
}
bool isEqual(const char* str) const {
return d == str;
}
bool isCustom() const {
return true;
}
private:
std::string d;
};
struct StringView : public Enumeration::Object {
StringView(const char* str) : d(str) {
}
const char* data() const {
return d.data();
}
bool isEqual(const char* str) const {
return d == str;
}
bool isCustom() const {
return false;
}
private:
std::string_view d;
};
}
Enumeration::Enumeration()
: _index(0)
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
{
}
Enumeration::Enumeration(const Enumeration &other)
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
{
enumArray = other.enumArray;
if (other._ownEnumArray) {
setEnums(other.getEnumVector());
} else {
_EnumArray = other._EnumArray;
}
_ownEnumArray = other._ownEnumArray;
_index = other._index;
_maxVal = other._maxVal;
}
Enumeration::Enumeration(const char *valStr)
: _index(0)
: _ownEnumArray(true), _index(0), _maxVal(0)
{
enumArray.push_back(std::make_shared<StringCopy>(valStr));
setValue(valStr);
_EnumArray = new const char*[2];
#if defined (_MSC_VER)
_EnumArray[0] = _strdup(valStr);
#else
_EnumArray[0] = strdup(valStr);
#endif
_EnumArray[1] = nullptr;
}
Enumeration::Enumeration(const char **list, const char *valStr)
: _index(0)
: _EnumArray(list), _ownEnumArray(false)
{
while (list && *list) {
enumArray.push_back(std::make_shared < StringView>(*list));
list++;
}
findMaxVal();
setValue(valStr);
}
Enumeration::~Enumeration()
{
enumArray.clear();
if (_ownEnumArray) {
if (_EnumArray != nullptr) {
tearDown();
}
}
}
void Enumeration::tearDown(void)
{
// Ugly...
for(char **plEnums = (char **)_EnumArray; *plEnums != nullptr; ++plEnums) {
// Delete C Strings first
free(*plEnums);
}
delete [] _EnumArray;
_EnumArray = nullptr;
_ownEnumArray = false;
_maxVal = -1;
}
void Enumeration::setEnums(const char **plEnums)
{
if(plEnums == _EnumArray)
return;
std::string oldValue;
bool preserve = (isValid() && plEnums != nullptr);
if (preserve) {
@@ -111,15 +106,23 @@ void Enumeration::setEnums(const char **plEnums)
oldValue = str;
}
enumArray.clear();
while (plEnums && *plEnums) {
enumArray.push_back(std::make_shared<StringView>(*plEnums));
plEnums++;
// set _ownEnumArray
if (isValid() && _ownEnumArray) {
tearDown();
}
// set...
_EnumArray = plEnums;
// set _maxVal
findMaxVal();
// set _index
if (_index < 0)
_index = 0;
else if (_index > _maxVal)
_index = _maxVal;
if (preserve) {
setValue(oldValue);
}
@@ -140,14 +143,30 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
oldValue = str;
}
enumArray.clear();
for (std::vector<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) {
enumArray.push_back(std::make_shared<StringCopy>(it->c_str()));
if (isValid() && _ownEnumArray) {
tearDown();
}
// set _index
_EnumArray = new const char*[values.size() + 1];
int i = 0;
for (std::vector<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) {
#if defined (_MSC_VER)
_EnumArray[i++] = _strdup(it->c_str());
#else
_EnumArray[i++] = strdup(it->c_str());
#endif
}
_EnumArray[i] = nullptr; // null termination
// Other state variables
_maxVal = static_cast<int>(values.size() - 1);
_ownEnumArray = true;
if (_index < 0)
_index = 0;
else if (_index > _maxVal)
_index = _maxVal;
if (preserve) {
setValue(oldValue);
}
@@ -155,18 +174,36 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
void Enumeration::setValue(const char *value)
{
_index = 0;
for (std::size_t i = 0; i < enumArray.size(); i++) {
if (enumArray[i]->isEqual(value)) {
_index = static_cast<int>(i);
// using string methods without set, use setEnums(const char** plEnums) first!
//assert(_EnumArray);
if (!_EnumArray) {
_index = 0;
return;
}
int i = 0;
const char **plEnums = _EnumArray;
// search for the right entry
while (1) {
// end of list? set zero
if (*plEnums == nullptr) {
_index = 0;
break;
}
if (strcmp(*plEnums, value) == 0) {
_index = i;
break;
}
++plEnums;
++i;
}
}
void Enumeration::setValue(long value, bool checkRange)
{
if (value >= 0 && value < countItems()) {
if (value >= 0 && value <= _maxVal) {
_index = value;
} else {
if (checkRange) {
@@ -179,104 +216,116 @@ void Enumeration::setValue(long value, bool checkRange)
bool Enumeration::isValue(const char *value) const
{
// using string methods without set, use setEnums(const char** plEnums) first!
//assert(_EnumArray);
int i = getInt();
if (i == -1) {
return false;
} else {
return enumArray[i]->isEqual(value);
return strcmp(_EnumArray[i], value) == 0;
}
}
bool Enumeration::contains(const char *value) const
{
if (!isValid()) {
// using string methods without set, use setEnums(const char** plEnums) first!
//assert(_EnumArray);
if (!getEnums()) {
return false;
}
for (const auto& it : enumArray) {
if (it->isEqual(value))
return true;
}
const char **plEnums = _EnumArray;
return false;
// search for the right entry
while (1) {
// end of list?
if (*plEnums == nullptr)
return false;
if (strcmp(*plEnums, value) == 0)
return true;
++plEnums;
}
}
const char * Enumeration::getCStr() const
const char * Enumeration::getCStr(void) const
{
if (!isValid() || _index < 0 || _index >= countItems()) {
// using string methods without set, use setEnums(const char** plEnums) first!
//assert(_EnumArray);
if (!isValid() || _index < 0 || _index > _maxVal) {
return nullptr;
}
return enumArray[_index]->data();
return _EnumArray[_index];
}
int Enumeration::getInt() const
int Enumeration::getInt(void) const
{
if (!isValid() || _index < 0 || _index >= countItems()) {
if (!isValid() || _index < 0 || _index > _maxVal) {
return -1;
}
return _index;
}
std::vector<std::string> Enumeration::getEnumVector() const
std::vector<std::string> Enumeration::getEnumVector(void) const
{
std::vector<std::string> list;
for (const auto& it : enumArray)
list.emplace_back(it->data());
return list;
}
// using string methods without set, use setEnums(const char** plEnums) first!
if (!_EnumArray)
return std::vector<std::string>();
bool Enumeration::hasEnums() const
{
return (!enumArray.empty());
}
std::vector<std::string> result;
const char **plEnums = _EnumArray;
bool Enumeration::isValid() const
{
return (!enumArray.empty() && _index >= 0 && _index < countItems());
}
int Enumeration::maxValue() const
{
int num = -1;
if (!enumArray.empty())
num = static_cast<int>(enumArray.size()) - 1;
return num;
}
bool Enumeration::isCustom() const
{
for (const auto& it : enumArray) {
if (it->isCustom())
return true;
// end of list?
while (*plEnums != nullptr) {
result.push_back(*plEnums);
++plEnums;
}
return false;
return result;
}
const char ** Enumeration::getEnums(void) const
{
return _EnumArray;
}
bool Enumeration::isValid(void) const
{
return (_EnumArray != nullptr && _index >= 0 && _index <= _maxVal);
}
Enumeration & Enumeration::operator=(const Enumeration &other)
{
if (this == &other)
return *this;
if (other._ownEnumArray) {
setEnums(other.getEnumVector());
} else {
_EnumArray = other._EnumArray;
}
enumArray = other.enumArray;
_ownEnumArray = other._ownEnumArray;
_index = other._index;
_maxVal = other._maxVal;
return *this;
}
bool Enumeration::operator==(const Enumeration &other) const
{
if (_index != other._index || enumArray.size() != other.enumArray.size()) {
if(_index != other._index || _maxVal != other._maxVal)
return false;
}
for (size_t i = 0; i < enumArray.size(); ++i) {
if (enumArray[i]->data() == other.enumArray[i]->data())
if (_EnumArray == other._EnumArray)
return true;
for (int i=0; i<=_maxVal; ++i) {
if (_EnumArray[i] == other._EnumArray[i])
continue;
if (enumArray[i]->data() == nullptr || other.enumArray[i]->data() == nullptr)
if (_EnumArray[i] == nullptr || other._EnumArray[i] == nullptr)
return false;
if (!enumArray[i]->isEqual(other.enumArray[i]->data()))
if (strcmp(_EnumArray[i], other._EnumArray[i]) != 0)
return false;
}
return true;
@@ -291,7 +340,24 @@ bool Enumeration::operator==(const char *other) const
return (strcmp(getCStr(), other) == 0);
}
int Enumeration::countItems() const
void Enumeration::findMaxVal(void)
{
return static_cast<int>(enumArray.size());
if (_EnumArray == nullptr) {
_maxVal = -1;
return;
}
const char **plEnums = _EnumArray;
// the NULL terminator doesn't belong to the range of
// valid values
int i = -1;
while (*(plEnums++) != nullptr) {
++i;
// very unlikely to have enums with more then 5000 entries!
assert(i < 5000);
}
_maxVal = i;
}
+114 -110
View File
@@ -24,13 +24,14 @@
#ifndef BASE_ENUMERATION_H
#define BASE_ENUMERATION_H
#include <memory>
#include <string>
#include <vector>
#include <FCGlobal.h>
namespace App
{
class PropertyEnumeration;
/// A bidirectional string-integer mapping
/*!
* This is mainly intended for two purposes: working around the difficulty
@@ -51,141 +52,144 @@ namespace App
*/
class AppExport Enumeration
{
public:
class Object {
friend class App::PropertyEnumeration;
public:
virtual ~Object() {}
virtual const char* data() const = 0;
virtual bool isEqual(const char*) const = 0;
virtual bool isCustom() const = 0;
};
/// Constructs an empty Enumeration object
Enumeration();
public:
/// Constructs an empty Enumeration object
Enumeration();
/// Standard copy constructor
Enumeration(const Enumeration& other);
/// Standard copy constructor
Enumeration(const Enumeration& other);
/// Constructs an Enumeration with a single element
Enumeration(const char *valStr);
/// Constructs an Enumeration with a single element
Enumeration(const char *valStr);
/// Constructs an Enumeration using val within list
Enumeration(const char **list, const char *valStr);
/// Constructs an Enumeration using val within list
Enumeration(const char **list, const char *valStr);
/// Standard destructor
~Enumeration();
/// Standard destructor
~Enumeration();
/** Sets the enumeration string list
* The list is a NULL terminated array of pointers to const
* char* strings.
* \code
* const char enums[] = {"Black","White","Other",NULL}
* \endcode
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*
* Enumeration does not take ownership of the passed object
*/
void setEnums(const char **plEnums);
/** Sets the enumeration string list
* The list is a NULL terminated array of pointers to const
* char* strings.
* \code
* const char enums[] = {"Black","White","Other",NULL}
* \endcode
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*
* Enumeration does not take ownership of the passed object
*/
void setEnums(const char **plEnums);
/// Set all enum values as vector of strings
/*!
* This method causes the Enumeration to dynamically allocate
* it's own array of C Strings, which will be deleted by the
* destructor or subsequent calls to setEnums(). So, it is
* important to make sure the Enumeration stays in scope as
* long as values returned by getCStr are in use.
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*/
void setEnums(const std::vector<std::string> &values);
/// Set all enum values as vector of strings
/*!
* This method causes the Enumeration to dynamically allocate
* it's own array of C Strings, which will be deleted by the
* destructor or subsequent calls to setEnums(). So, it is
* important to make sure the Enumeration stays in scope as
* long as values returned by getCStr are in use.
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*/
void setEnums(const std::vector<std::string> &values);
/// Set the enum using a C string
void setValue(const char *value);
/// Set the enum using a C string
void setValue(const char *value);
/// Overload of setValue(const char *value)
void setValue(const std::string &value) {setValue(value.c_str());}
/// Overload of setValue(const char *value)
void setValue(const std::string &value) {setValue(value.c_str());}
/// Set the enum using a long
/*!
* if checkRange is set to true, throws Base::ValueError when
* values are set out of range
*
* Checks for boundaries via assert()
*/
void setValue(long value, bool checkRange = false);
/// Set the enum using a long
/*!
* if checkRange is set to true, throws Base::ValueError when
* values are set out of range
*
* Checks for boundaries via assert()
*/
void setValue(long value, bool checkRange = false);
/// Checks if the property is set to a certain string value
bool isValue(const char *value) const;
/// Checks if the property is set to a certain string value
bool isValue(const char *value) const;
/// Checks if a string is included in the enumeration
bool contains(const char *value) const;
/// Checks if a string is included in the enumeration
bool contains(const char *value) const;
/// Return the value as C string
/*!
* Returns NULL if the enumeration is invalid.
*/
const char * getCStr(void) const;
/// Return the value as C string
/*!
* Returns NULL if the enumeration is invalid.
*/
const char * getCStr() const;
/// Return value as integer
/*!
* Returns -1 if the Enumeration isn't valid
*/
int getInt(void) const;
/// Return value as integer
/*!
* Returns -1 if the Enumeration isn't valid
*/
int getInt() const;
/// get all possible enum values as vector of strings
std::vector<std::string> getEnumVector(void) const;
/// get all possible enum values as vector of strings
std::vector<std::string> getEnumVector() const;
/// get pointer to the enum list
const char ** getEnums(void) const;
/// returns true if the enum list is non-empty, false otherwise
bool hasEnums() const;
/// Returns true if the instance is in a usable state
bool isValid(void) const;
/// Returns true if the instance is in a usable state
bool isValid() const;
/// Returns the highest usable integer value for this enum
/*!
* Returns -1 if the enumeration is not valid according to isValid()
*/
int maxValue(void) const {return _maxVal;}
/// Returns the highest usable integer value for this enum
/*!
* Returns -1 if the enumeration is not valid according to isValid()
*/
int maxValue() const;
/// Assignment operator
Enumeration & operator=(const Enumeration &other);
/// Returns true if any of the items is a user-defined string
bool isCustom() const;
/// true iff our string representation matches other's
/*!
* Returns false if either Enumeration is not valid.
*/
bool operator==(const Enumeration &other) const;
/// Assignment operator
Enumeration & operator=(const Enumeration &other);
/// true iff our string representation matches other
/*!
* Returns false if Enumeration is not valid.
*/
bool operator==(const char *other) const;
protected:
/// Returns true if instance was not initialized via static string list
bool isCustom(void) const {return _ownEnumArray;}
/// true iff our string representation matches other's
/*!
* Returns false if either Enumeration is not valid.
*/
bool operator==(const Enumeration &other) const;
/// Updates _maxVal
void findMaxVal(void);
/// true iff our string representation matches other
/*!
* Returns false if Enumeration is not valid.
*/
bool operator==(const char *other) const;
protected:
/// De-allocates memory used in _EnumArray
/*!
* Important to not call this unless this Enumeration owns array.
*/
void tearDown(void);
/// Number of items
int countItems() const;
private:
/// Handle to C Strings of possible enumeration values
const char **_EnumArray;
private:
/// Handle to C Strings of possible enumeration values
using ObjectPtr = std::shared_ptr<Object>;
std::vector<ObjectPtr> enumArray;
/// Whether instance owns _EnumArray
bool _ownEnumArray;
/// Integer value of the enumeration
/*!
* This serves as an index into enumArray to get the string
* representation.
*/
int _index;
/// Integer value of the enumeration
/*!
* This serves as an index into _EnumArray to get the string
* representation.
*/
int _index;
friend class PropertyEnumeration;
/*! Cached result from findMaxVal()
* Value should either be the maximum allowable integer value for
* the Enumeration, or -1 if not initialized
*/
int _maxVal;
}; // class Enumeration
} // namespace App
+1 -1
View File
@@ -3193,7 +3193,7 @@ static int column;
// show the parser the lexer method
#define yylex ExpressionParserlex
int ExpressionParserlex(void);
int ExpressionParserlex();
// Parser, defined in ExpressionParser.y
# define YYTOKENTYPE
+21 -21
View File
@@ -43,7 +43,7 @@ ExtensionContainer::ExtensionContainer() {
ExtensionContainer::~ExtensionContainer() {
//we need to delete all dynamically added extensions
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.second->isPythonExtension())
delete entry.second;
}
@@ -56,7 +56,7 @@ void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext)
//no duplicate extensions (including base classes)
if(hasExtension(extension)) {
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
_extensions.erase(entry.first);
break;
@@ -73,7 +73,7 @@ bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
bool found = _extensions.find(t) != _extensions.end();
if(!found && derived) {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return true;
}
@@ -85,7 +85,7 @@ bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
bool ExtensionContainer::hasExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.second->name() == name)
return true;
}
@@ -98,11 +98,11 @@ Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_
auto result = _extensions.find(t);
if((result == _extensions.end()) && derived) {
//we need to check for derived types
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.first.isDerivedFrom(t))
return entry.second;
}
if(no_except)
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
@@ -111,7 +111,7 @@ Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_
return result->second;
}
else {
if(no_except)
if(no_except)
return nullptr;
//if we arrive here we don't have anything matching
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
@@ -126,7 +126,7 @@ bool ExtensionContainer::hasExtensions() const {
Extension* ExtensionContainer::getExtension(const std::string& name) const {
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.second->name() == name)
return entry.second;
}
@@ -137,7 +137,7 @@ std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Typ
std::vector<Extension*> vec;
//and for types derived from it, as they can be cast to the extension
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
if(entry.first.isDerivedFrom(type))
vec.push_back(entry.second);
}
@@ -146,13 +146,13 @@ std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Typ
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
App::PropertyContainer::getPropertyList(List);
for(const auto& entry : _extensions)
for(auto entry : _extensions)
entry.second->extensionGetPropertyList(List);
}
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
App::PropertyContainer::getPropertyMap(Map);
for(const auto& entry : _extensions)
for(auto entry : _extensions)
entry.second->extensionGetPropertyMap(Map);
}
@@ -161,7 +161,7 @@ Property* ExtensionContainer::getPropertyByName(const char* name) const {
if(prop)
return prop;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
auto prop = entry.second->extensionGetPropertyByName(name);
if(prop)
return prop;
@@ -176,7 +176,7 @@ short int ExtensionContainer::getPropertyType(const Property* prop) const {
if(res != 0)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyType(prop);
if(res != 0)
return res;
@@ -191,7 +191,7 @@ short int ExtensionContainer::getPropertyType(const char* name) const {
if(res != 0)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyType(name);
if(res != 0)
return res;
@@ -207,7 +207,7 @@ const char* ExtensionContainer::getPropertyName(const Property* prop) const {
if(res != nullptr)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyName(prop);
if(res != nullptr)
return res;
@@ -222,7 +222,7 @@ const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
if(res != nullptr)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(prop);
if(res != nullptr)
return res;
@@ -237,7 +237,7 @@ const char* ExtensionContainer::getPropertyGroup(const char* name) const {
if(res != nullptr)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyGroup(name);
if(res != nullptr)
return res;
@@ -253,7 +253,7 @@ const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) c
if(res != nullptr)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(prop);
if(res != nullptr)
return res;
@@ -268,7 +268,7 @@ const char* ExtensionContainer::getPropertyDocumentation(const char* name) const
if(res != nullptr)
return res;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
res = entry.second->extensionGetPropertyDocumentation(name);
if(res != nullptr)
return res;
@@ -281,7 +281,7 @@ void ExtensionContainer::onChanged(const Property* prop) {
//inform all extensions about changed property. This includes all properties from the
//extended object (this) as well as all extension properties
for(const auto& entry : _extensions)
for(auto entry : _extensions)
entry.second->extensionOnChanged(prop);
App::PropertyContainer::onChanged(prop);
@@ -318,7 +318,7 @@ void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
//save dynamic extensions
writer.incInd(); // indentation for 'Extensions'
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">" << std::endl;
for(const auto& entry : _extensions) {
for(auto entry : _extensions) {
auto ext = entry.second;
writer.incInd(); // indentation for 'Extension name'
+1 -63
View File
@@ -132,74 +132,12 @@ public:
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(),derived,no_except));
}
/** Helpers for iterator over extensions of a given type */
//@{
/** Helper structs to deduce the class type of a class function pointer type */
//@{
template<typename T> struct ClassOf {};
template<typename R, typename C>
struct ClassOf<R (C::*)>{ using type = C; };
//@}
/** Call an extension member function for each extension of the given type
* @param f: the member function pointer of some extension class
* @param args: variadic parameters passed to the member function
*/
template<typename F, class... Args>
void callExtension(F&& f, Args&&... args) const {
for (const auto &entry : _extensions) {
if(entry.first.isDerivedFrom(ClassOf<F>::type::getExtensionClassTypeId()))
(static_cast<typename ClassOf<F>::type*>(entry.second)->*f)(std::forward<Args>(args)...);
}
}
/** Query using an extension member function
* @param f: the member function pointer of some extension class
* @param args: variadic parameters passed to the member function
*
* @return Returns true if the iteratorion is terminated prematurely, or else false.
*
* The iteration over the contained extensions is terminated as soon as the
* extension method call returns true.
*/
template<typename F, class... Args>
bool queryExtension(F&& f, Args&&... args) const {
for (const auto &entry : _extensions) {
if(entry.first.isDerivedFrom(ClassOf<F>::type::getExtensionClassTypeId())) {
if((static_cast<typename ClassOf<F>::type*>(entry.second)->*f)(std::forward<Args>(args)...))
return true;
}
}
return false;
}
/** Invoke a callable for each extension of a given type
* @param f: the callable that accepts one argument of an extension, and
* returns any value that is convertible to boolean.
*
* @return Returns true if the iteratorion is terminated prematurely, or else false.
*
* The iteration over the contained extensions is terminated as soon as the
* extension method call returns true.
*/
template<typename T, typename F>
bool foreachExtension(F f) const {
for (const auto &entry : _extensions) {
if(entry.first.isDerivedFrom(T::getExtensionClassTypeId())) {
if(f(static_cast<T*>(entry.second)))
return true;
}
}
return false;
}
//get all extensions which have the given base class
std::vector<Extension*> getExtensionsDerivedFrom(Base::Type type) const;
template<typename ExtensionT>
std::vector<ExtensionT*> getExtensionsDerivedFromType() const {
std::vector<ExtensionT*> typevec;
for (const auto &entry : _extensions) {
for(auto entry : _extensions) {
if(entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId()))
typevec.push_back(static_cast<ExtensionT*>(entry.second));
}
+2 -2
View File
@@ -174,11 +174,11 @@ PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
char *type;
PyObject *deriv = Py_True;
if (!PyArg_ParseTuple(args, "s|O!", &type, &PyBool_Type, &deriv))
if (!PyArg_ParseTuple(args, "s|O", &type, &deriv))
return nullptr;
//get the extension type asked for
bool derived = PyObject_IsTrue(deriv) ? true : false;
bool derived = PyObject_IsTrue(deriv);
Base::Type extension = Base::Type::fromName(type);
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
std::stringstream str;
-5
View File
@@ -48,11 +48,6 @@ public:
}
virtual ~ExtensionPythonT() {
}
ExtensionPythonT(const ExtensionPythonT&) = delete;
ExtensionPythonT(ExtensionPythonT&&) = delete;
ExtensionPythonT& operator= (const ExtensionPythonT&) = delete;
ExtensionPythonT& operator= (ExtensionPythonT&&) = delete;
};
typedef ExtensionPythonT<App::Extension> ExtensionPython;
-5
View File
@@ -85,11 +85,6 @@ protected:
virtual void onSettingDocument() {
FeatureT::onSettingDocument();
}
FeatureCustomT(const FeatureCustomT&) = delete;
FeatureCustomT(FeatureCustomT&&) = delete;
FeatureCustomT& operator= (const FeatureCustomT&) = delete;
FeatureCustomT& operator= (FeatureCustomT&&) = delete;
};
} //namespace App
-6
View File
@@ -342,12 +342,6 @@ protected:
FeatureT::onDocumentRestored();
}
public:
FeaturePythonT(const FeaturePythonT&) = delete;
FeaturePythonT(FeaturePythonT&&) = delete;
FeaturePythonT& operator= (const FeaturePythonT&) = delete;
FeaturePythonT& operator= (FeaturePythonT&&) = delete;
private:
FeaturePythonImp* imp;
PropertyPythonObject Proxy;
+4 -37
View File
@@ -100,7 +100,7 @@ FeatureTest::FeatureTest()
ADD_PROPERTY_TYPE(TypeTransient,(4711),group,Prop_Transient ,"An example property which has the type 'Transient'" );
ADD_PROPERTY_TYPE(TypeNoRecompute,(4711),group,Prop_NoRecompute,"An example property which has the type 'NoRecompute'");
ADD_PROPERTY_TYPE(TypeAll ,(4711),group,(App::PropertyType) (Prop_Output|Prop_ReadOnly |Prop_Hidden ),
"An example property which has the types 'Output', 'ReadOnly' and 'Hidden'");
"An example property which has the types 'Output', 'ReadOnly', and 'Hidden'");
ADD_PROPERTY(QuantityLength,(1.0));
QuantityLength.setUnit(Base::Unit::Length);
@@ -118,46 +118,13 @@ FeatureTest::~FeatureTest()
}
short FeatureTest::mustExecute() const
short FeatureTest::mustExecute(void) const
{
return DocumentObject::mustExecute();
}
DocumentObjectExecReturn *FeatureTest::execute()
DocumentObjectExecReturn *FeatureTest::execute(void)
{
// Enum handling
Enumeration enumObj1 = Enum.getEnum();
enumObj1.setValue(7, false);
enumObj1.setValue(4, true);
Enumeration enumObj2 = Enum.getEnum();
enumObj2.setValue(4, true);
Enumeration enumObj3(enumObj2);
const char* val = enumObj3.getCStr();
enumObj3.isValue(val);
enumObj3.getEnumVector();
Enumeration enumObj4("Single item");
enumObj4.setEnums(enums);
std::ignore = enumObj4 == enumObj2;
enumObj4.setEnums(nullptr);
enumObj4 = enumObj2;
std::ignore = enumObj4 == enumObj4.getCStr();
Enumeration enumObj5(enums, enums[3]);
enumObj5.isValue(enums[2]);
enumObj5.isValue(enums[3]);
enumObj5.contains(enums[1]);
Enumeration enumObj6;
enumObj6.setEnums(enums);
enumObj6.setValue(enums[1]);
std::vector<std::string> list;
list.emplace_back("Hello");
list.emplace_back("World");
enumObj6.setEnums(list);
enumObj6.setValue(list.back());
/*
doc=App.newDocument()
obj=doc.addObject("App::FeatureTest")
@@ -222,7 +189,7 @@ FeatureTestException::FeatureTestException()
ADD_PROPERTY(ExceptionType,(Base::Exception::getClassTypeId().getKey()) );
}
DocumentObjectExecReturn *FeatureTestException::execute()
DocumentObjectExecReturn *FeatureTestException::execute(void)
{
//ExceptionType;
throw Base::RuntimeError("FeatureTestException::execute(): Testexception ;-)");
+8 -129
View File
@@ -25,15 +25,10 @@
#include <App/GeoFeaturePy.h>
#include <Base/Console.h>
#include <App/Link.h>
#include "ComplexGeoData.h"
#include "Document.h"
#include "GeoFeature.h"
#include "GeoFeatureGroupExtension.h"
#include "MappedElement.h"
#include "ComplexGeoData.h"
FC_LOG_LEVEL_INIT("GeoFeature",true,true)
using namespace App;
@@ -48,8 +43,6 @@ PROPERTY_SOURCE(App::GeoFeature, App::DocumentObject)
GeoFeature::GeoFeature(void)
{
ADD_PROPERTY_TYPE(Placement,(Base::Placement()),nullptr,Prop_NoRecompute,nullptr);
ADD_PROPERTY_TYPE(_ElementMapVersion,(""),"Base",
(App::PropertyType)(Prop_Output|Prop_Hidden|Prop_Transient),"");
}
GeoFeature::~GeoFeature(void)
@@ -88,48 +81,16 @@ PyObject* GeoFeature::getPyObject(void)
}
std::pair<std::string,std::string>
GeoFeature::getElementName(const char *name, ElementNameType type) const
std::pair<std::string,std::string> GeoFeature::getElementName(
const char *name, ElementNameType type) const
{
(void)type;
std::pair<std::string,std::string> ret;
if(!name)
if(!name)
return ret;
auto prop = getPropertyOfGeometry();
if(!prop) return std::make_pair("", name);
auto geo = prop->getComplexData();
if(!geo) return std::make_pair("", name);
return _getElementName(name, geo->getElementName(name));
}
std::pair<std::string,std::string>
GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) const
{
std::pair<std::string,std::string> ret;
if (mapped.index && mapped.name) {
std::ostringstream ss;
ss << Data::ComplexGeoData::elementMapPrefix()
<< mapped.name << '.' << mapped.index;
ret.first = ss.str();
mapped.index.toString(ret.second);
} else if (mapped.name) {
FC_TRACE("element mapped name " << name << " not found in " << getFullName());
ret.first = name;
const char *dot = strrchr(name,'.');
if(dot) {
// deliberately mangle the old style element name to signal a
// missing reference
ret.second = Data::ComplexGeoData::missingPrefix();
ret.second += dot+1;
}
} else {
mapped.index.toString(ret.second);
}
ret.second = name;
return ret;
}
@@ -138,8 +99,6 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
ElementNameType type, const DocumentObject *filter,
const char **_element, GeoFeature **geoFeature)
{
elementName.first.clear();
elementName.second.clear();
if(!obj || !obj->getNameInDocument())
return nullptr;
if(!subname)
@@ -149,16 +108,11 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
auto sobj = obj->getSubObject(subname);
if(!sobj)
return nullptr;
auto linked = sobj->getLinkedObject(true);
auto geo = Base::freecad_dynamic_cast<GeoFeature>(linked);
if(!geo && linked) {
auto ext = linked->getExtensionByType<LinkBaseExtension>(true);
if(ext)
geo = Base::freecad_dynamic_cast<GeoFeature>(ext->getTrueLinkedObject(true));
}
obj = sobj->getLinkedObject(true);
auto geo = dynamic_cast<GeoFeature*>(obj);
if(geoFeature)
*geoFeature = geo;
if(filter && geo!=filter)
if(!obj || (filter && obj!=filter))
return nullptr;
if(!element || !element[0]) {
if(append)
@@ -185,78 +139,3 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
return sobj;
}
bool GeoFeature::hasMissingElement(const char *subname) {
return Data::ComplexGeoData::hasMissingElement(subname);
if(!subname)
return false;
auto dot = strrchr(subname,'.');
if(!dot)
return subname[0]=='?';
return dot[1]=='?';
}
void GeoFeature::updateElementReference() {
auto prop = getPropertyOfGeometry();
if(!prop) return;
auto geo = prop->getComplexData();
if(!geo) return;
bool reset = false;
auto version = getElementMapVersion(prop);
if(_ElementMapVersion.getStrValue().empty())
_ElementMapVersion.setValue(version);
else if(_ElementMapVersion.getStrValue()!=version) {
reset = true;
_ElementMapVersion.setValue(version);
}
PropertyLinkBase::updateElementReferences(this,reset);
}
void GeoFeature::onChanged(const Property *prop) {
if(prop==getPropertyOfGeometry()) {
if(getDocument() && !getDocument()->testStatus(Document::Restoring)
&& !getDocument()->isPerformingTransaction())
{
updateElementReference();
}
}
DocumentObject::onChanged(prop);
}
void GeoFeature::onDocumentRestored() {
if(!getDocument()->testStatus(Document::Status::Importing))
_ElementMapVersion.setValue(getElementMapVersion(getPropertyOfGeometry(),true));
DocumentObject::onDocumentRestored();
}
const std::vector<std::string>&
GeoFeature::searchElementCache(const std::string &element,
bool checkGeometry,
double tol,
double atol) const
{
static std::vector<std::string> none;
(void)element;
(void)checkGeometry;
(void)tol;
(void)atol;
return none;
}
const std::vector<const char *>&
GeoFeature::getElementTypes(bool /*all*/) const
{
static std::vector<const char *> nil;
auto prop = getPropertyOfGeometry();
if (!prop)
return nil;
return prop->getComplexData()->getElementTypes();
}
std::vector<Data::IndexedName>
GeoFeature::getHigherElements(const char *element, bool silent) const
{
auto prop = getPropertyOfGeometry();
if (!prop)
return {};
return prop->getComplexData()->getHigherElements(element, silent);
}
+3 -55
View File
@@ -24,9 +24,7 @@
#ifndef APP_GEOFEATURE_H
#define APP_GEOFEATURE_H
#include <memory>
#include "DocumentObject.h"
#include "MappedElement.h"
#include "PropertyGeo.h"
@@ -42,7 +40,6 @@ class AppExport GeoFeature : public App::DocumentObject
public:
PropertyPlacement Placement;
PropertyString _ElementMapVersion;
/// Constructor
GeoFeature(void);
@@ -83,17 +80,10 @@ public:
* @param name: input name
* @param type: desired element name type to return
*
* This function relies on ComplexGeoData::elementMapPrefix() to decide
* whether it is a forward query, i.e. mapped -> original, or reverse
* query. The reason being that, unlike ComplexGeoData who deals with the
* actual element map data, GeoFeature here sits at a higher level.
* GeoFeature should be dealing with whatever various PropertyLinkSub(s) is
* assigned.
* @return a pair(newName,oldName). New element name may be empty.
*
* This function is made virtual, so that inherited class can do something
* unusual, such as Sketcher::SketcherObject, which uses this to expose its
* private geometries without a corresponding TopoShape, and yet being
* source code compatible.
* This function currently is does nothing. The new style element name
* generation will be added in the next batch of patches.
*/
virtual std::pair<std::string,std::string> getElementName(
const char *name, ElementNameType type=Normal) const;
@@ -117,8 +107,6 @@ public:
bool append=false, ElementNameType type=Normal,
const DocumentObject *filter=nullptr,const char **element=nullptr, GeoFeature **geo=nullptr);
static bool hasMissingElement(const char *subname);
/**
* @brief Calculates the placement in the global reference coordinate system
*
@@ -132,46 +120,6 @@ public:
* @return Base::Placement The transformation from the global reference coordinate system
*/
Base::Placement globalPlacement() const;
/** Search sub element using internal cached geometry
*
* @param element: element name
* @param checkGeometry: search element by comparing geometry
* @param tol: coordinate tolerance
* @param atol: angle tolerance
*
* @return Returns a list of found element reference to the new goemetry.
* The returned value will be invalidated when the geometry is changed.
*
* Before changing the property of geometry, GeoFeature will internally
* make a snapshot of all referenced element geometry. After change, user
* code may call this function to search for the new element name that
* reference to the same geometry of the old element.
*/
virtual const std::vector<std::string>& searchElementCache(const std::string &element,
bool checkGeometry = true,
double tol = 1e-7,
double atol = 1e-10) const;
/// Return the object that owns the shape that contains the give element name
virtual DocumentObject *getElementOwner(const Data::MappedName & /*name*/) const
{return nullptr;}
virtual const std::vector<const char *>& getElementTypes(bool all=true) const;
/// Return the higher level element names of the given element
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
protected:
virtual void onChanged(const Property* prop);
virtual void onDocumentRestored();
void updateElementReference();
std::pair<std::string,std::string> _getElementName(const char *name, const Data::MappedElement &mapped) const;
private:
std::vector<Data::MappedElement> _elementMapCache;
std::string _elementMapVersion;
};
} //namespace App
+11 -3
View File
@@ -256,12 +256,12 @@ PyObject* GroupExtensionPy::getObject(PyObject *args)
PyObject* GroupExtensionPy::hasObject(PyObject *args)
{
PyObject *object;
PyObject *recursivePy = Py_False;
if (!PyArg_ParseTuple(args, "O!|O!", &(DocumentObjectPy::Type), &object, &PyBool_Type, &recursivePy))
PyObject *recursivePy = nullptr;
int recursive = 0;
if (!PyArg_ParseTuple(args, "O!|O", &(DocumentObjectPy::Type), &object, &recursivePy))
return nullptr;
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
bool recursive = PyObject_IsTrue(recursivePy) ? true : false;
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->getNameInDocument()) {
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an invalid object");
return nullptr;
@@ -270,6 +270,14 @@ PyObject* GroupExtensionPy::hasObject(PyObject *args)
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an object from another document with this group");
return nullptr;
}
if (recursivePy) {
recursive = PyObject_IsTrue(recursivePy);
if ( recursive == -1) {
// Note: shouldn't happen
PyErr_SetString(PyExc_ValueError, "The recursive parameter should be of boolean type");
return nullptr;
}
}
bool v = getGroupExtensionPtr()->hasObject(docObj->getDocumentObjectPtr(), recursive);
return PyBool_FromLong(v ? 1 : 0);
+20 -85
View File
@@ -148,7 +148,7 @@ void LinkParams::removeCopyOnChangeApplyToAll() {
EXTENSION_PROPERTY_SOURCE(App::LinkBaseExtension, App::DocumentObjectExtension)
LinkBaseExtension::LinkBaseExtension(void)
LinkBaseExtension::LinkBaseExtension()
:enableLabelCache(false),hasOldSubElement(false),hasCopyOnChange(true)
{
initExtensionType(LinkBaseExtension::getExtensionClassTypeId());
@@ -166,7 +166,7 @@ LinkBaseExtension::~LinkBaseExtension()
{
}
PyObject* LinkBaseExtension::getExtensionPyObject(void) {
PyObject* LinkBaseExtension::getExtensionPyObject() {
if (ExtensionPythonObject.is(Py::_None())){
// ref counter is set to 1
ExtensionPythonObject = Py::Object(new LinkBaseExtensionPy(this),true);
@@ -232,14 +232,14 @@ void LinkBaseExtension::setProperty(int idx, Property *prop) {
case PropLinkMode: {
static const char *linkModeEnums[] = {"None","Auto Delete","Auto Link","Auto Unlink",nullptr};
auto propLinkMode = static_cast<PropertyEnumeration*>(prop);
if(!propLinkMode->hasEnums())
if(!propLinkMode->getEnums())
propLinkMode->setEnums(linkModeEnums);
break;
}
case PropLinkCopyOnChange: {
static const char *enums[] = {"Disabled","Enabled","Owned","Tracking",nullptr};
auto propEnum = static_cast<PropertyEnumeration*>(prop);
if(!propEnum->hasEnums())
if(!propEnum->getEnums())
propEnum->setEnums(enums);
break;
}
@@ -293,7 +293,7 @@ void LinkBaseExtension::setProperty(int idx, Property *prop) {
static const char _GroupPrefix[] = "Configuration (";
App::DocumentObjectExecReturn *LinkBaseExtension::extensionExecute(void) {
App::DocumentObjectExecReturn *LinkBaseExtension::extensionExecute() {
// The actual value of LinkTouched is not important, just to notify view
// provider that the link (in fact, its dependents, i.e. linked ones) have
// recomputed.
@@ -398,7 +398,7 @@ App::DocumentObjectExecReturn *LinkBaseExtension::extensionExecute(void) {
return inherited::extensionExecute();
}
short LinkBaseExtension::extensionMustExecute(void) {
short LinkBaseExtension::extensionMustExecute() {
auto link = getLink();
if(!link)
return 0;
@@ -905,6 +905,7 @@ void LinkBaseExtension::monitorOnChangeCopyObjects(
if (getLinkCopyOnChangeValue() == CopyOnChangeDisabled)
return;
for(auto obj : objs) {
obj->setStatus(App::ObjectStatus::TouchOnColorChange, true);
copyOnChangeSrcConns.push_back(obj->signalChanged.connect(
[this](const DocumentObject &, const Property &) {
if (auto prop = this->getLinkCopyOnChangeTouchedProperty()) {
@@ -1011,7 +1012,7 @@ int LinkBaseExtension::extensionSetElementVisible(const char *element, bool visi
return -1;
}
int LinkBaseExtension::extensionIsElementVisible(const char *element) const {
int LinkBaseExtension::extensionIsElementVisible(const char *element) {
int index = _getShowElementValue()?getElementIndex(element):getArrayIndex(element);
if(index>=0) {
auto propElementVis = getVisibilityListProperty();
@@ -1408,21 +1409,12 @@ bool LinkBaseExtension::extensionGetSubObject(DocumentObject *&ret, const char *
void LinkBaseExtension::checkGeoElementMap(const App::DocumentObject *obj,
const App::DocumentObject *linked, PyObject **pyObj, const char *postfix) const
{
if(!pyObj || !*pyObj || !PyObject_TypeCheck(*pyObj, &Data::ComplexGeoDataPy::Type))
if(!pyObj || !*pyObj || (!postfix && obj->getDocument()==linked->getDocument()) ||
!PyObject_TypeCheck(*pyObj, &Data::ComplexGeoDataPy::Type))
return;
auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
std::string _postfix;
if (linked && obj && linked->getDocument() != obj->getDocument()) {
_postfix = Data::ComplexGeoData::externalTagPostfix();
if (postfix) {
if (!boost::starts_with(postfix, Data::ComplexGeoData::elementMapPrefix()))
_postfix += Data::ComplexGeoData::elementMapPrefix();
_postfix += postfix;
}
postfix = _postfix.c_str();
}
geoData->reTagElementMap(obj->getID(),obj->getDocument()->getStringHasher(),postfix);
// auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
// geoData->reTagElementMap(obj->getID(),obj->getDocument()->Hasher,postfix);
}
void LinkBaseExtension::onExtendedUnsetupObject() {
@@ -2185,12 +2177,10 @@ void LinkBaseExtension::expandSubname(std::string &subname) const {
}
static bool isExcludedProperties(const char *name) {
if (boost::equals(name, "Shape"))
return true;
if (boost::equals(name, "Proxy"))
return true;
if (boost::equals(name, "Placement"))
return true;
#define CHECK_EXCLUDE_PROP(_name) if(strcmp(name,#_name)==0) return true;
CHECK_EXCLUDE_PROP(Shape);
CHECK_EXCLUDE_PROP(Proxy);
CHECK_EXCLUDE_PROP(Placement);
return false;
}
@@ -2214,61 +2204,6 @@ Property *LinkBaseExtension::extensionGetPropertyByName(const char* name) const
return nullptr;
}
std::vector<std::string> LinkBaseExtension::getHiddenSubnames(
const App::DocumentObject *obj, const char *prefix)
{
std::vector<std::string> res;
if(!obj || !obj->getNameInDocument())
return res;
PropertyLinkSubHidden *prop;
int depth=0;
while((prop=Base::freecad_dynamic_cast<PropertyLinkSubHidden>(
obj->getPropertyByName("ColoredElements"))))
{
for(auto &v : prop->getShadowSubs()) {
if(prefix && !boost::starts_with(v.first,prefix) && !boost::starts_with(v.second,prefix))
continue;
auto &s = v.second;
if(boost::ends_with(s,DocumentObject::hiddenMarker()))
res.push_back(s.substr(0,s.size()-DocumentObject::hiddenMarker().size()));
}
auto o = Base::freecad_dynamic_cast<DocumentObject>(prop->getContainer());
if(!o)
break;
o = o->getLinkedObject(false);
if(o==obj || !GetApplication().checkLinkDepth(++depth,true))
break;
obj = o;
}
return res;
}
bool LinkBaseExtension::isSubnameHidden(const App::DocumentObject *obj, const char *subname)
{
if(!obj || !obj->getNameInDocument() || !subname || !subname[0])
return false;
PropertyLinkSubHidden *prop;
int depth=0;
while((prop=Base::freecad_dynamic_cast<PropertyLinkSubHidden>(
obj->getPropertyByName("ColoredElements"))))
{
for(auto &v : prop->getShadowSubs()) {
if((boost::starts_with(v.first,subname) || boost::starts_with(v.second,subname))
&& boost::ends_with(v.second, DocumentObject::hiddenMarker()))
return true;
}
auto o = Base::freecad_dynamic_cast<DocumentObject>(prop->getContainer());
if(!o)
break;
o = o->getLinkedObject(false);
if(o==obj || !GetApplication().checkLinkDepth(++depth,true))
break;
obj = o;
}
return false;
}
bool LinkBaseExtension::isLinkMutated() const
{
return getLinkCopyOnChangeValue() != CopyOnChangeDisabled
@@ -2291,7 +2226,7 @@ template class AppExport ExtensionPythonT<LinkBaseExtension>;
EXTENSION_PROPERTY_SOURCE(App::LinkExtension, App::LinkBaseExtension)
LinkExtension::LinkExtension(void)
LinkExtension::LinkExtension()
{
initExtensionType(LinkExtension::getExtensionClassTypeId());
@@ -2331,7 +2266,7 @@ bool Link::canLinkProperties() const {
namespace App {
PROPERTY_SOURCE_TEMPLATE(App::LinkPython, App::Link)
template<> const char* App::LinkPython::getViewProviderName(void) const {
template<> const char* App::LinkPython::getViewProviderName() const {
return "Gui::ViewProviderLinkPython";
}
template class AppExport FeaturePythonT<App::Link>;
@@ -2358,7 +2293,7 @@ bool LinkElement::canDelete() const {
namespace App {
PROPERTY_SOURCE_TEMPLATE(App::LinkElementPython, App::LinkElement)
template<> const char* App::LinkElementPython::getViewProviderName(void) const {
template<> const char* App::LinkElementPython::getViewProviderName() const {
return "Gui::ViewProviderLinkPython";
}
template class AppExport FeaturePythonT<App::LinkElement>;
@@ -2377,7 +2312,7 @@ LinkGroup::LinkGroup() {
namespace App {
PROPERTY_SOURCE_TEMPLATE(App::LinkGroupPython, App::LinkGroup)
template<> const char* App::LinkGroupPython::getViewProviderName(void) const {
template<> const char* App::LinkGroupPython::getViewProviderName() const {
return "Gui::ViewProviderLinkPython";
}
template class AppExport FeaturePythonT<App::LinkGroup>;
+8 -13
View File
@@ -286,17 +286,17 @@ public:
bool extensionGetLinkedObject(DocumentObject *&ret,
bool recurse, Base::Matrix4D *mat, bool transform, int depth) const override;
virtual App::DocumentObjectExecReturn *extensionExecute(void) override;
virtual short extensionMustExecute(void) override;
virtual App::DocumentObjectExecReturn *extensionExecute() override;
virtual short extensionMustExecute() override;
virtual void extensionOnChanged(const Property* p) override;
virtual void onExtendedUnsetupObject () override;
virtual void onExtendedDocumentRestored() override;
virtual int extensionSetElementVisible(const char *, bool) override;
virtual int extensionIsElementVisible(const char *) const override;
virtual int extensionIsElementVisible(const char *) override;
virtual bool extensionHasChildElement() const override;
virtual PyObject* getExtensionPyObject(void) override;
virtual PyObject* getExtensionPyObject() override;
virtual Property *extensionGetPropertyByName(const char* name) const override;
@@ -304,11 +304,6 @@ public:
int getElementIndex(const char *subname, const char **psubname=nullptr) const;
void elementNameFromIndex(int idx, std::ostream &ss) const;
static std::vector<std::string> getHiddenSubnames(
const App::DocumentObject *obj, const char *prefix=0);
static bool isSubnameHidden(const App::DocumentObject *obj, const char *subname);
DocumentObject *getContainer();
const DocumentObject *getContainer() const;
@@ -541,9 +536,9 @@ public:
LINK_PROPS_DEFINE(LINK_PARAMS_LINK)
Link(void);
Link();
const char* getViewProviderName(void) const override{
const char* getViewProviderName() const override{
return "Gui::ViewProviderLink";
}
@@ -586,7 +581,7 @@ public:
LINK_PROPS_DEFINE(LINK_PARAMS_ELEMENT)
LinkElement();
const char* getViewProviderName(void) const override{
const char* getViewProviderName() const override{
return "Gui::ViewProviderLink";
}
@@ -625,7 +620,7 @@ public:
LinkGroup();
const char* getViewProviderName(void) const override{
const char* getViewProviderName() const override{
return "Gui::ViewProviderLink";
}
-258
View File
@@ -1,258 +0,0 @@
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* 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 <cstdlib>
# include <unordered_set>
#endif
#include <QHash>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include "DocumentObject.h"
#include "MappedElement.h"
using namespace Data;
struct ByteArray
{
ByteArray(const QByteArray &b)
:bytes(b)
{}
ByteArray(const ByteArray &other)
:bytes(other.bytes)
{}
ByteArray(ByteArray &&other)
:bytes(std::move(other.bytes))
{}
void mutate() const
{
QByteArray copy;
copy.append(bytes.constData(), bytes.size());
bytes = copy;
}
bool operator==(const ByteArray & other) const {
return bytes == other.bytes;
}
mutable QByteArray bytes;
};
struct ByteArrayHasher
{
std::size_t operator()(const ByteArray &bytes) const
{
return qHash(bytes.bytes);
}
std::size_t operator()(const QByteArray &bytes) const
{
return qHash(bytes);
}
};
void IndexedName::set(const char *name,
int len,
const std::vector<const char*> &types,
bool allowOthers)
{
static std::unordered_set<ByteArray, ByteArrayHasher> NameSet;
if (len < 0)
len = static_cast<int>(std::strlen(name));
int i;
for (i=len-1; i>=0; --i) {
if (name[i]<'0' || name[i]>'9')
break;
}
++i;
this->index = std::atoi(name+i);
for (int j=0; j<i; ++j) {
if (name[j] == '_'
|| (name[j] >= 'a' && name[j] <= 'z' )
|| (name[j] >= 'A' && name[j] <= 'Z'))
continue;
this->type = "";
return;
}
for (const char * type : types) {
int j=0;
for (const char *n=name, *t=type; *n; ++n) {
if (*n != *t || j >= i)
break;
++j;
++t;
if (!*t) {
this->type = type;
return;
}
}
}
if (allowOthers) {
auto res = NameSet.insert(QByteArray::fromRawData(name, i));
if (res.second)
res.first->mutate();
this->type = res.first->bytes.constData();
} else
this->type = "";
}
void MappedName::compact() const
{
auto self = const_cast<MappedName*>(this);
if (this->raw) {
self->data = QByteArray(self->data.constData(), self->data.size());
self->raw = false;
}
#if 0
static std::unordered_set<QByteArray, ByteArrayHasher> PostfixSet;
if (this->postfix.size()) {
auto res = PostfixSet.insert(this->postfix);
if (!res.second)
self->postfix = *res.first;
}
#endif
}
bool ElementNameComp::operator()(const MappedName &a, const MappedName &b) const {
size_t size = std::min(a.size(),b.size());
if(!size)
return a.size()<b.size();
size_t i=0;
if(b[0] == '#') {
if(a[0]!='#')
return true;
// If both string starts with '#', compare the following hex digits by
// its integer value.
int res = 0;
for(i=1;i<size;++i) {
unsigned char ac = (unsigned char)a[i];
unsigned char bc = (unsigned char)b[i];
if(std::isxdigit(bc)) {
if(!std::isxdigit(ac))
return true;
if(res==0) {
if(ac<bc)
res = -1;
else if(ac>bc)
res = 1;
}
}else if(std::isxdigit(ac))
return false;
else
break;
}
if(res < 0)
return true;
else if(res > 0)
return false;
for (; i<size; ++i) {
char ac = a[i];
char bc = b[i];
if (ac < bc)
return true;
if (ac > bc)
return false;
}
return a.size()<b.size();
}
else if (a[0] == '#')
return false;
// If the string does not start with '#', compare the non-digits prefix
// using lexical order.
for(i=0;i<size;++i) {
unsigned char ac = (unsigned char)a[i];
unsigned char bc = (unsigned char)b[i];
if(!std::isdigit(bc)) {
if(std::isdigit(ac))
return true;
if(ac<bc)
return true;
if(ac>bc)
return false;
} else if(!std::isdigit(ac)) {
return false;
} else
break;
}
// Then compare the following digits part by integer value
int res = 0;
for(;i<size;++i) {
unsigned char ac = (unsigned char)a[i];
unsigned char bc = (unsigned char)b[i];
if(std::isdigit(bc)) {
if(!std::isdigit(ac))
return true;
if(res==0) {
if(ac<bc)
res = -1;
else if(ac>bc)
res = 1;
}
}else if(std::isdigit(ac))
return false;
else
break;
}
if(res < 0)
return true;
else if(res > 0)
return false;
// Finally, compare the remaining tail using lexical order
for (; i<size; ++i) {
char ac = a[i];
char bc = b[i];
if (ac < bc)
return true;
if (ac > bc)
return false;
}
return a.size()<b.size();
}
HistoryItem::HistoryItem(App::DocumentObject *obj, const Data::MappedName &name)
:obj(obj),tag(0),element(name)
{
if(obj)
tag = obj->getID();
}
const std::string & MappedChildElements::prefix()
{
static std::string _prefix(ComplexGeoData::elementMapPrefix() + ":R");
return _prefix;
}
-847
View File
@@ -1,847 +0,0 @@
/****************************************************************************
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* 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 _AppMappedElement_h_
#define _AppMappedElement_h_
#include <cstring>
#include <memory>
#include <cctype>
#include <boost/algorithm/string/predicate.hpp>
#include <QByteArray>
#include <QHash>
#include "ComplexGeoData.h"
#include "StringHasher.h"
namespace App
{
class DocumentObject;
}
namespace Data
{
class AppExport IndexedName {
public:
explicit IndexedName(const char *name = nullptr, int _index = 0)
: index(0)
{
if (!name)
this->type = "";
else {
set(name);
if (_index)
this->index = _index;
}
}
IndexedName(const char *name,
const std::vector<const char*> & types,
bool allowOthers=true)
{
set(name, -1, types, allowOthers);
}
explicit IndexedName(const QByteArray & data)
{
set(data.constData(), data.size());
}
IndexedName(const IndexedName &other)
: type(other.type), index(other.index)
{}
static IndexedName fromConst(const char *name, int index) {
IndexedName res;
res.type = name;
res.index = index;
return res;
}
IndexedName & operator=(const IndexedName & other)
{
this->index = other.index;
this->type = other.type;
return *this;
}
friend std::ostream & operator<<(std::ostream & s, const IndexedName & e)
{
s << e.type;
if (e.index > 0)
s << e.index;
return s;
}
bool operator==(const IndexedName & other) const
{
return this->index == other.index
&& (this->type == other.type
|| std::strcmp(this->type, other.type)==0);
}
IndexedName & operator+=(int offset)
{
this->index += offset;
assert(this->index >= 0);
return *this;
}
IndexedName & operator++()
{
++this->index;
return *this;
}
IndexedName & operator--()
{
--this->index;
assert(this->index >= 0);
return *this;
}
bool operator!=(const IndexedName & other) const
{
return !(this->operator==(other));
}
const char * toString(std::string & s) const
{
// Note! s is not cleared on purpose.
std::size_t offset = s.size();
s += this->type;
if (this->index > 0)
s += std::to_string(this->index);
return s.c_str() + offset;
}
int compare(const IndexedName & other) const
{
int res = std::strcmp(this->type, other.type);
if (res)
return res;
if (this->index < other.index)
return -1;
if (this->index > other.index)
return 1;
return 0;
}
bool operator<(const IndexedName & other) const
{
return compare(other) < 0;
}
char operator[](int index) const
{
return this->type[index];
}
const char * getType() const { return this->type; }
int getIndex() const { return this->index; }
void setIndex(int index) { assert(index>=0); this->index = index; }
bool isNull() const { return !this->type[0]; }
explicit operator bool() const { return !isNull(); }
protected:
void set(const char *,
int len = -1,
const std::vector<const char *> &types = {},
bool allowOthers = true);
private:
const char * type;
int index;
};
class AppExport MappedName
{
public:
MappedName()
:raw(false)
{}
#if QT_VERSION >= 0x050200
MappedName(MappedName &&other)
:data(std::move(other.data))
,postfix(std::move(other.postfix))
,raw(other.raw)
{}
MappedName & operator=(MappedName &&other)
{
this->data = std::move(other.data);
this->postfix = std::move(other.postfix);
this->raw = other.raw;
return *this;
}
#endif
explicit MappedName(const char * name, int size = -1)
:raw(false)
{
if (!name) return;
if (boost::starts_with(name, ComplexGeoData::elementMapPrefix()))
name += ComplexGeoData::elementMapPrefix().size();
if (size < 0)
data = QByteArray(name);
else
data = QByteArray(name, size);
}
explicit MappedName(const std::string & name)
{
int size = name.size();
const char *n = name.c_str();
if (boost::starts_with(name, ComplexGeoData::elementMapPrefix())) {
n += ComplexGeoData::elementMapPrefix().size();
size -= ComplexGeoData::elementMapPrefix().size();
}
data = QByteArray(n, size);
}
explicit MappedName(const IndexedName & element)
:data(element.getType()), raw(false)
{
if (element.getIndex() > 0)
data += QByteArray::number(element.getIndex());
}
explicit MappedName(const App::StringIDRef & sid)
:raw(false)
{
sid.toBytes(this->data);
}
MappedName(const MappedName & other)
:data(other.data), postfix(other.postfix), raw(other.raw)
{}
MappedName(const MappedName & other, int from, int size = -1)
: raw(false)
{
append(other, from, size);
}
MappedName(const MappedName & other, const char *postfix)
:data(other.data + other.postfix)
,postfix(postfix)
,raw(false)
{}
static MappedName fromRawData(const char * name, int size = -1)
{
MappedName res;
if (name) {
res.data = QByteArray::fromRawData(name,
size>=0 ? size: qstrlen(name));
res.raw = true;
}
return res;
}
static MappedName fromRawData(const QByteArray & data)
{
return fromRawData(data.constData(), data.size());
}
static MappedName fromRawData(const MappedName &other, int from, int size = -1)
{
if (from < 0)
from = 0;
if (from >= other.size())
return MappedName();
if (from >= other.data.size())
return MappedName(other, from, size);
MappedName res;
res.raw = true;
if (size < 0)
size = other.size() - from;
if (size < other.data.size()-from)
res.data = QByteArray::fromRawData(
other.data.constData()+from, size);
else {
res.data = QByteArray::fromRawData(
other.data.constData()+from, other.data.size()-from);
size -= other.data.size() - from;
if (size == other.postfix.size())
res.postfix = other.postfix;
else if (size)
res.postfix.append(other.postfix.constData(), size);
}
return res;
}
MappedName & operator=(const MappedName & other)
{
this->data = other.data;
this->postfix = other.postfix;
this->raw = other.raw;
return *this;
}
MappedName & operator=(const std::string & other)
{
*this = MappedName(other);
return *this;
}
MappedName & operator=(const char * other)
{
*this = MappedName(other);
return *this;
}
friend std::ostream & operator<<(std::ostream & s, const MappedName & n)
{
s.write(n.data.constData(), n.data.size());
s.write(n.postfix.constData(), n.postfix.size());
return s;
}
bool operator==(const MappedName & other) const
{
if (this->size() != other.size())
return false;
if (this->data.size() == other.data.size())
return this->data == other.data && this->postfix == other.postfix;
const auto &a = this->data.size() < other.data.size() ? *this : other;
const auto &b = this->data.size() < other.data.size() ? other: *this;
if (!b.data.startsWith(a.data))
return false;
QByteArray tmp = QByteArray::fromRawData(
b.data.constData() + a.data.size(),
b.data.size() - a.data.size());
if (!a.postfix.startsWith(tmp))
return false;
tmp = QByteArray::fromRawData(
a.postfix.constData() + tmp.size(),
a.postfix.size() - tmp.size());
return tmp == b.postfix;
}
bool operator!=(const MappedName & other) const
{
return !(this->operator==(other));
}
MappedName operator+(const MappedName & other) const
{
MappedName res(*this);
res += other;
return res;
}
MappedName operator+(const char * other) const
{
MappedName res(*this);
res += other;
return res;
}
MappedName operator+(const std::string & other) const
{
MappedName res(*this);
res += other;
return res;
}
MappedName operator+(const QByteArray & other) const
{
MappedName res(*this);
res += other;
return res;
}
MappedName & operator+=(const char * other)
{
if (other && other[0])
this->postfix.append(other, -1);
return *this;
}
MappedName & operator+=(const std::string & other)
{
if (other.size()) {
this->postfix.reserve(this->postfix.size() + other.size());
this->postfix.append(other.c_str(), other.size());
}
return *this;
}
MappedName & operator+=(const QByteArray & other)
{
this->postfix += other;
return *this;
}
MappedName & operator+=(const MappedName & other)
{
append(other);
return *this;
}
void append(const char * d, int size = -1)
{
if (d && size) {
if (size < 0)
size = qstrlen(d);
if (empty())
this->data.append(d, size);
else
this->postfix.append(d, size);
}
}
void append(const MappedName & other, int from = 0, int size = -1)
{
if (from < 0)
from = 0;
else if (from > other.size())
return;
if (size < 0 || size + from > other.size())
size = other.size() - from;
int count = size;
if (from < other.data.size()) {
if (count > other.data.size() - from)
count = other.data.size() - from;
if (from == 0 && count == other.data.size() && this->empty()) {
this->data = other.data;
this->raw = other.raw;
} else
append(other.data.constData() + from, count);
from = 0;
size -= count;
} else
from -= other.data.size();
if (size) {
if (from == 0 && size == other.postfix.size()) {
if (this->empty())
this->data = other.postfix;
else if (this->postfix.isEmpty())
this->postfix = other.postfix;
else
this->postfix += other.postfix;
} else
append(other.postfix.constData() + from, size);
}
}
std::string toString(int from, int len=-1) const
{
std::string res;
return toString(res, from, len);
}
const char * toString(std::string &s, int from=0, int len=-1) const
{
std::size_t offset = s.size();
int count = this->size();
if (from < 0)
from = 0;
else if (from >= count)
return s.c_str()+s.size();
if (len < 0 || len > count - from)
len = count - from;
s.reserve(s.size() + len);
if (from < this->data.size()) {
count = this->data.size() - from;
if (len < count)
count = len;
s.append(this->data.constData()+from, count);
len -= count;
}
s.append(this->postfix.constData(), len);
return s.c_str() + offset;
}
const char * toConstString(int offset, int &size) const
{
if (offset < 0)
offset = 0;
if (offset > this->data.size()) {
offset -= this->data.size();
if (offset > this->postfix.size()) {
size = 0;
return "";
}
size = this->postfix.size() - offset;
return this->postfix.constData() + offset;
}
size = this->data.size() - offset;
return this->data.constData() + offset;
}
QByteArray toRawBytes(int offset=0, int size=-1) const
{
if (offset < 0)
offset = 0;
if (offset >= this->size())
return QByteArray();
if (size < 0 || size > this->size() - offset)
size = this->size() - offset;
if (offset >= this->data.size()) {
offset -= this->data.size();
return QByteArray::fromRawData(this->postfix.constData()+offset, size);
}
if (size <= this->data.size() - offset)
return QByteArray::fromRawData(this->data.constData()+offset, size);
QByteArray res(this->data.constData()+offset, this->data.size()-offset);
res.append(this->postfix.constData(), size - this->data.size() + offset);
return res;
}
const QByteArray & dataBytes() const
{
return this->data;
}
const QByteArray & postfixBytes() const
{
return this->postfix;
}
const char * constPostfix() const
{
return this->postfix.constData();
}
// No constData() because 'data' is allow to contain raw data, which may
// not end with 0.
#if 0
void char * constData() const
{
return this->data.constData();
}
#endif
QByteArray toBytes() const
{
if (this->postfix.isEmpty())
return this->data;
if (this->data.isEmpty())
return this->postfix;
return this->data + this->postfix;
}
IndexedName toIndexedName() const
{
if (this->postfix.isEmpty())
return IndexedName(this->data);
return IndexedName();
}
std::string toPrefixedString() const
{
std::string res;
toPrefixedString(res);
return res;
}
const char *toPrefixedString(std::string &buf) const
{
if (!toIndexedName())
buf += ComplexGeoData::elementMapPrefix();
toString(buf);
return buf.c_str();
}
int compare(const MappedName &other) const
{
int asize = this->size();
int bsize = other.size();
for (int i=0, count=std::min(asize, bsize); i<count; ++i) {
char a = this->operator[](i);
char b = other[i];
if (a < b)
return -1;
if (a > b)
return 1;
}
if (asize < bsize)
return -1;
if (asize > bsize)
return 1;
return 0;
}
bool operator<(const MappedName & other) const
{
return compare(other) < 0;
}
char operator[](int index) const
{
if (index >= this->data.size())
return this->postfix[index - this->data.size()];
return this->data[index];
}
int size() const
{
return this->data.size() + this->postfix.size();
}
bool empty() const
{
return this->data.isEmpty() && this->postfix.isEmpty();
}
bool isRaw() const
{
return this->raw;
}
MappedName copy() const
{
if (!this->raw)
return *this;
MappedName res;
res.data.append(this->data.constData(), this->data.size());
res.postfix = this->postfix;
return res;
}
void compact() const;
explicit operator bool() const
{
return !empty();
}
void clear()
{
this->data.clear();
this->postfix.clear();
this->raw = false;
}
int find(const char *d, int from = 0) const
{
if (!d)
return -1;
if (from < 0)
from = 0;
if (from < this->data.size()) {
int res = this->data.indexOf(d, from);
if (res >= 0)
return res;
from = 0;
} else
from -= this->data.size();
int res = this->postfix.indexOf(d, from);
if (res < 0)
return res;
return res + this->data.size();
}
int find(const std::string &d, int from = 0) const
{
return find(d.c_str(), from);
}
int rfind(const char *d, int from = -1) const
{
if (!d)
return -1;
if (from < 0 || from > this->postfix.size()) {
if (from > postfix.size())
from -= postfix.size();
int res = this->postfix.lastIndexOf(d, from);
if (res >= 0)
return res + this->data.size();
from = -1;
}
return this->data.lastIndexOf(d, from);
}
int rfind(const std::string &d, int from = -1) const
{
return rfind(d.c_str(), from);
}
bool endsWith(const char *s) const
{
if (!s)
return false;
if (this->postfix.size())
return this->postfix.endsWith(s);
return this->data.endsWith(s);
}
bool endsWith(const std::string &s) const
{
return endsWith(s.c_str());
}
bool startsWith(const QByteArray & s, int offset = 0) const
{
if (s.size() > size() - offset)
return false;
if (offset || (this->data.size() && this->data.size() < s.size()))
return toRawBytes(offset, s.size()) == s;
if (this->data.size())
return this->data.startsWith(s);
return this->postfix.startsWith(s);
}
bool startsWith(const char *s, int offset = 0) const
{
if (!s)
return false;
return startsWith(QByteArray::fromRawData(s, qstrlen(s)), offset);
}
bool startsWith(const std::string &s, int offset = 0) const
{
return startsWith(QByteArray::fromRawData(s.c_str(), s.size()), offset);
}
std::size_t hash() const
{
#if QT_VERSION >= 0x050000
return qHash(data, qHash(postfix));
#else
return qHash(data) ^ qHash(postfix);
#endif
}
private:
QByteArray data;
QByteArray postfix;
bool raw;
};
struct AppExport MappedElement
{
IndexedName index;
MappedName name;
MappedElement()
{}
MappedElement(const IndexedName & idx, const MappedName & n)
: index(idx), name(n)
{}
MappedElement(const MappedName & n, const IndexedName & idx)
: index(idx), name(n)
{}
MappedElement(const MappedElement & other)
: index(other.index), name(other.name)
{}
MappedElement(MappedElement && other)
: index(std::move(other.index)), name(std::move(other.name))
{}
MappedElement & operator=(MappedElement && other)
{
this->index = std::move(other.index);
this->name = std::move(other.name);
return *this;
}
MappedElement & operator=(const MappedElement & other)
{
this->index = other.index;
this->name = other.name;
return *this;
}
bool operator==(const MappedElement &other) const
{
return this->index == other.index && this->name == other.name;
}
bool operator!=(const MappedElement &other) const
{
return this->index != other.index || this->name != other.name;
}
bool operator<(const MappedElement &other) const
{
int res = this->index.compare(other.index);
if (res < 0)
return true;
if (res > 0)
return false;
return this->name < other.name;
}
};
struct AppExport HistoryItem {
App::DocumentObject *obj;
long tag;
Data::MappedName element;
Data::IndexedName index;
std::vector<Data::MappedName> intermediates;
HistoryItem(App::DocumentObject *obj, const Data::MappedName &name);
};
struct AppExport ElementNameComp {
/** Comparison function to make topo name more stable
*
* The sorting decompose the name into either of the following two forms
* '#' + hex_digits + tail
* non_digits + digits + tail
*
* The non-digits part is compared lexically, while the digits part is
* compared by its integer value.
*
* The reason for this is to prevent name with bigger digits (usually means
* comes late in history) comes early when sorting.
*/
bool operator()(const MappedName &a, const MappedName &b) const;
};
typedef QVector<App::StringIDRef> ElementIDRefs;
struct AppExport MappedChildElements
{
IndexedName indexedName;
int count;
int offset;
long tag;
ElementMapPtr elementMap;
QByteArray postfix;
ElementIDRefs sids;
static const std::string & prefix();
};
} //namespace Data
#endif
+4 -5
View File
@@ -41,8 +41,8 @@ namespace App {
class XMLMergeReader : public Base::XMLReader
{
public:
XMLMergeReader(std::map<std::string, std::string>& name, Base::Reader &reader)
: Base::XMLReader(reader), nameMap(name)
XMLMergeReader(std::map<std::string, std::string>& name, const char* FileName, std::istream& str)
: Base::XMLReader(FileName, str), nameMap(name)
{}
void addName(const char* s1, const char* s2)
@@ -152,8 +152,7 @@ MergeDocuments::importObjects(std::istream& input)
{
this->nameMap.clear();
this->stream = new zipios::ZipInputStream(input);
Base::ZipReader zreader(*this->stream,std::string("<memory>"));
XMLMergeReader reader(this->nameMap, zreader);
XMLMergeReader reader(this->nameMap,"<memory>", *stream);
reader.setVerbose(isVerbose());
std::vector<App::DocumentObject*> objs = appdoc->importObjects(reader);
@@ -167,7 +166,7 @@ void MergeDocuments::importObject(const std::vector<App::DocumentObject*>& o, Ba
{
objects = o;
Restore(r);
r.readFiles();
r.readFiles(*this->stream);
}
void MergeDocuments::exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer & w)
+10 -2
View File
@@ -98,7 +98,11 @@ Metadata::Metadata(const fs::path& metadataFile)
auto errHandler = std::make_unique<MetadataInternal::XMLErrorHandler>();
_parser->setErrorHandler(errHandler.get());
#if defined (FC_OS_WIN32)
_parser->parse(reinterpret_cast<const XMLCh*>(metadataFile.wstring().c_str()));
#else
_parser->parse(metadataFile.string().c_str());
#endif
auto doc = _parser->getDocument();
_dom = doc->getDocumentElement();
@@ -448,6 +452,7 @@ bool Metadata::satisfies(const Meta::Dependency& dep)
std::map<std::string, std::string>& config = App::Application::Config();
replacements.insert(std::make_pair("$BuildVersionMajor", config["BuildVersionMajor"]));
replacements.insert(std::make_pair("$BuildVersionMinor", config["BuildVersionMinor"]));
replacements.insert(std::make_pair("$BuildVersionMinor", config["BuildVersionPoint"]));
replacements.insert(std::make_pair("$BuildRevision", config["BuildRevision"]));
for (const auto& replacement : replacements) {
auto pos = injectedString.find(replacement.first);
@@ -458,7 +463,7 @@ bool Metadata::satisfies(const Meta::Dependency& dep)
}
auto parsedExpression = App::Expression::parse(nullptr, dep.condition);
auto result = parsedExpression->eval();
if (!boost::any_cast<bool> (result->getValueAsAny()))
if (boost::any_cast<bool> (result->getValueAsAny()) == false)
return false;
}
@@ -492,7 +497,10 @@ bool App::Metadata::supportsCurrentFreeCAD() const
if (fcVersion == Meta::Version()) {
std::map<std::string, std::string>& config = App::Application::Config();
std::stringstream ss;
ss << config["BuildVersionMajor"] << "." << config["BuildVersionMinor"] << "." << (config["BuildRevision"].empty() ? "0" : config["BuildRevision"]);
ss << config["BuildVersionMajor"]
<< "." << config["BuildVersionMinor"]
<< "." << config["BuildVersionPoint"]
<< "." << (config["BuildRevision"].empty() ? "0" : config["BuildRevision"]);
fcVersion = Meta::Version(ss.str());
}
+14 -52
View File
@@ -28,18 +28,15 @@
#endif
#include <atomic>
#include <Base/Exception.h>
#include <Base/Tools.h>
#include <Base/Writer.h>
#include <CXX/Objects.hxx>
#include "Application.h"
#include "Document.h"
#include "DocumentObject.h"
#include "Property.h"
#include "ObjectIdentifier.h"
#include "PropertyContainer.h"
using namespace App;
@@ -81,40 +78,17 @@ bool Property::isValidName(const char* name)
return name && name[0] != '\0';
}
void Property::SetRestoreError(const char * msg)
{
if (auto doc = father->getOwnerDocument())
doc->setErrorDescription(this, msg);
}
std::string Property::getFullName(bool python) const {
if(!myName || (python && !father))
return std::string(python?"None":"?");
std::ostringstream ss;
if(father)
ss << father->getFullName(python)
<< '.' << father->getPropertyPrefix();
ss << myName;
return ss.str();
}
std::string Property::getFileName(const char *postfix, const char *prefix) const {
std::ostringstream ss;
if(prefix)
ss << prefix;
if(!myName)
ss << "Property";
else {
std::string name = getFullName();
auto pos = name.find('#');
if(pos == std::string::npos)
ss << name;
std::string Property::getFullName() const {
std::string name;
if(myName) {
if(father)
name = father->getFullName() + ".";
else
ss << (name.c_str()+pos+1);
}
if(postfix)
ss << postfix;
return ss.str();
name = "?.";
name += myName;
}else
return "?";
return name;
}
short Property::getType(void) const
@@ -239,15 +213,10 @@ void Property::destroy(Property *p) {
void Property::touch()
{
if(GetApplication().isClosingAll())
return;
PropertyCleaner guard(this);
StatusBits.set(Touched);
if (getName() && father) {
father->onEarlyChange(this);
if (father)
father->onChanged(this);
}
StatusBits.set(Touched);
}
void Property::setReadOnly(bool readOnly)
@@ -322,20 +291,13 @@ void Property::setStatus(Status pos, bool on) {
}
bool Property::isSame(const Property &other) const {
return isSameContent(other);
}
bool Property::isSameContent(const Property &other) const {
if(&other == this)
return true;
if(other.getTypeId() != getTypeId() || getMemSize() != other.getMemSize())
return false;
FC_STATIC Base::StringWriter writer,writer2;
writer.clear();
Base::StringWriter writer,writer2;
Save(writer);
writer2.clear();
other.Save(writer2);
return writer.getString() == writer2.getString();
}
+1 -18
View File
@@ -32,10 +32,6 @@
#include <string>
#include <FCGlobal.h>
// NOTE! define this to static thread_local if FreeCAD ever decides to use
// multi-threading recomputation.
#define FC_STATIC static
namespace Py {
class Object;
}
@@ -136,10 +132,7 @@ public:
*/
static bool isValidName(const char* name);
/** Return a fully qualified property name that include its own's name
* @param python: if true, then return an expression for accessing this property in Python
*/
virtual std::string getFullName(bool python=false) const;
std::string getFullName() const;
/// Get the class name of the associated property editor item
virtual const char* getEditorName(void) const { return ""; }
@@ -258,8 +251,6 @@ public:
/// Compare if this property has the same content as the given one
virtual bool isSame(const Property &other) const;
virtual void SetRestoreError(const char *) override;
/** Return a unique ID for the property
*
* The ID of a property is generated from a monotonically increasing
@@ -270,11 +261,6 @@ public:
*/
int64_t getID() const {return _id;}
/// Compare property by comparing their XML content
bool isSameContent(const Property &other) const;
virtual void beforeSave() const {}
friend class PropertyContainer;
friend struct PropertyData;
friend class DynamicProperty;
@@ -300,9 +286,6 @@ protected:
/// Verify a path for the current property
virtual void verifyPath(const App::ObjectIdentifier & p) const;
/// Return a file name suitable for saving this property
std::string getFileName(const char *postfix=0, const char *prefix=0) const;
private:
// forbidden
Property(const Property&);
+28 -100
View File
@@ -69,15 +69,15 @@ unsigned int PropertyContainer::getMemSize (void) const
App::Property* PropertyContainer::addDynamicProperty(
const char* type, const char* name, const char* group, const char* doc,
short attr, bool readonly, bool hidden)
short attr, bool ro, bool hidden)
{
return dynamicProps.addDynamicProperty(*this,type,name,group,doc,attr,readonly,hidden);
return dynamicProps.addDynamicProperty(*this,type,name,group,doc,attr,ro,hidden);
}
Property *PropertyContainer::getPropertyByName(const char* name) const
{
auto prop = dynamicProps.getDynamicPropertyByName(name);
if(prop)
if(prop)
return prop;
return getPropertyData().getPropertyByName(this,name);
}
@@ -121,7 +121,7 @@ short PropertyContainer::getPropertyType(const char *name) const
const char* PropertyContainer::getPropertyGroup(const Property* prop) const
{
auto group = dynamicProps.getPropertyGroup(prop);
if(group)
if(group)
return group;
return getPropertyData().getGroup(this,prop);
}
@@ -129,7 +129,7 @@ const char* PropertyContainer::getPropertyGroup(const Property* prop) const
const char* PropertyContainer::getPropertyGroup(const char *name) const
{
auto group = dynamicProps.getPropertyGroup(name);
if(group)
if(group)
return group;
return getPropertyData().getGroup(this,name);
}
@@ -137,7 +137,7 @@ const char* PropertyContainer::getPropertyGroup(const char *name) const
const char* PropertyContainer::getPropertyDocumentation(const Property* prop) const
{
auto doc = dynamicProps.getPropertyDocumentation(prop);
if(doc)
if(doc)
return doc;
return getPropertyData().getDocumentation(this,prop);
}
@@ -145,7 +145,7 @@ const char* PropertyContainer::getPropertyDocumentation(const Property* prop) co
const char* PropertyContainer::getPropertyDocumentation(const char *name) const
{
auto doc = dynamicProps.getPropertyDocumentation(name);
if(doc)
if(doc)
return doc;
return getPropertyData().getDocumentation(this,name);
}
@@ -221,52 +221,15 @@ void PropertyContainer::handleChangedPropertyType(XMLReader &reader, const char
PropertyData PropertyContainer::propertyData;
namespace App {
class PropertyContainerP
void PropertyContainer::Save (Base::Writer &writer) const
{
public:
std::map<std::string, Property*> propertyMap;
std::vector<Property*> transients;
void clear()
{
propertyMap.clear();
transients.clear();
}
};
struct PropertyContainerPGuard
{
PropertyContainerPGuard(PropertyContainerP & priv)
:priv(priv)
{}
~PropertyContainerPGuard()
{
priv.clear();
}
PropertyContainerP & priv;
};
}
void PropertyContainer::beforeSave() const
{
if (!_pimpl)
_pimpl.reset(new PropertyContainerP);
else
_pimpl->clear();
auto & Map = _pimpl->propertyMap;
auto & transients = _pimpl->transients;
std::map<std::string,Property*> Map;
getPropertyMap(Map);
std::vector<Property*> transients;
for(auto it=Map.begin();it!=Map.end();) {
auto prop = it->second;
if (prop->getContainer() != this
|| prop->testStatus(Property::PropNoPersist))
{
if(prop->testStatus(Property::PropNoPersist)) {
it = Map.erase(it);
continue;
}
@@ -276,22 +239,9 @@ void PropertyContainer::beforeSave() const
{
transients.push_back(prop);
it = Map.erase(it);
} else {
prop->beforeSave();
}else
++it;
}
}
}
void PropertyContainer::Save (Base::Writer &writer) const
{
if (!_pimpl || _pimpl->propertyMap.empty())
beforeSave();
PropertyContainerPGuard guard(*_pimpl);
auto & Map = _pimpl->propertyMap;
auto & transients = _pimpl->transients;
writer.incInd(); // indentation for 'Properties Count'
writer.Stream() << writer.ind() << "<Properties Count=\"" << Map.size()
@@ -325,8 +275,8 @@ void PropertyContainer::Save (Base::Writer &writer) const
if(it->second->testStatus(Property::Transient)
|| it->second->getType() & Prop_Transient)
{
writer.Stream() << "</Property>\n";
writer.decInd();
writer.Stream() << "</Property>" << std::endl;
continue;
}
@@ -376,21 +326,14 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
reader.readElement("_Property");
Property* prop = getPropertyByName(reader.getAttribute("name"));
if(prop)
FC_TRACE("restore transient '" << prop->getFullName() << "'");
if(prop && reader.hasAttribute("status")) {
decltype(Property::StatusBits) status(reader.getAttributeAsUnsigned("status"));
status.reset(Property::User1);
status.reset(Property::User2);
status.reset(Property::User3);
prop->setStatusValue(status.to_ulong());
}
FC_TRACE("restore transient '" << prop->getName() << "'");
if(prop && reader.hasAttribute("status"))
prop->setStatusValue(reader.getAttributeAsUnsigned("status"));
}
for (int i=0 ;i<Cnt ;i++) {
int guard;
reader.readElement("Property",&guard);
reader.readElement("Property");
std::string PropName = reader.getAttribute("name");
Base::ReaderContext rctx(PropName);
std::string TypeName = reader.getAttribute("type");
// NOTE: We must also check the type of the current property because a
// subclass of PropertyContainer might change the type of a property but
@@ -403,13 +346,7 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
decltype(Property::StatusBits) status;
if(reader.hasAttribute("status")) {
status = decltype(Property::StatusBits)(reader.getAttributeAsUnsigned("status"));
// User1~3 are currently reserved for various temporary usage.
// To avoid some potential problems, no persistence at the moment.
status.reset(Property::User1);
status.reset(Property::User2);
status.reset(Property::User3);
status = decltype(status)(reader.getAttributeAsUnsigned("status"));
if(prop)
prop->setStatusValue(status.to_ulong());
}
@@ -420,10 +357,10 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
&& !status.test(Property::PropTransient)
&& !prop->testStatus(Property::PropTransient))
{
FC_TRACE("restoring property " << prop->getFullName());
FC_TRACE("restore property '" << prop->getName() << "'");
prop->Restore(reader);
}else
FC_TRACE("skip transient " << prop->getFullName());
FC_TRACE("skip transient '" << prop->getName() << "'");
}
// name matches but not the type
else if (prop) {
@@ -440,38 +377,29 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
reader.clearPartialRestoreProperty();
}
}
catch (Base::XMLParseException &e) {
FC_ERR(e.what() << " while parsing " << getFullName() << '.' << PropName);
e.setReported(true);
catch (const Base::XMLParseException&) {
throw; // re-throw
}
catch (const Base::RestoreError &e) {
e.ReportException();
catch (const Base::RestoreError &) {
reader.setPartialRestore(true);
reader.clearPartialRestoreProperty();
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
<< "): was subject to a partial restore.");
Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str());
}
catch (const Base::Exception &e) {
e.ReportException();
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
<< ") restore error.");
Base::Console().Error("%s\n", e.what());
}
catch (const std::exception &e) {
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
<< ") restore error: " << e.what());
Base::Console().Error("%s\n", e.what());
}
catch (const char* e) {
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
<< ") restore error: " << e);
Base::Console().Error("%s\n", e);
}
#ifndef FC_DEBUG
catch (...) {
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
<< ") restore error: Unknown C++ exception thrown\n");
Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown\n");
}
#endif
reader.readEndElement("Property",&guard);
reader.readEndElement("Property");
}
reader.readEndElement("Properties");
}
+4 -25
View File
@@ -40,7 +40,6 @@ namespace App
class Property;
class PropertyContainer;
class DocumentObject;
class Document;
class Extension;
enum PropertyType
@@ -136,7 +135,6 @@ struct AppExport PropertyData
void split(PropertyData *other);
};
class PropertyContainerP;
/** Base class of all classes with properties
*/
@@ -160,17 +158,7 @@ public:
virtual unsigned int getMemSize (void) const;
/** Return a fully qualified name for this container
* @param python: if true, then return an expression for accessing this container in Python
*/
virtual std::string getFullName(bool python=false) const {
(void)python;
return std::string();
}
/// Return owner document of this container
virtual App::Document *getOwnerDocument() const
{return nullptr;}
virtual std::string getFullName() const {return std::string();}
/// find a property by its name
virtual Property *getPropertyByName(const char* name) const;
@@ -208,7 +196,7 @@ public:
virtual App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool readonly=false, bool hidden=false);
short attr=0, bool ro=false, bool hidden=false);
DynamicProperty::PropData getDynamicPropertyData(const Property* prop) const {
return dynamicProps.getDynamicPropertyData(prop);
@@ -232,7 +220,6 @@ public:
virtual void Save (Base::Writer &writer) const;
virtual void Restore(Base::XMLReader &reader);
virtual void beforeSave() const;
virtual void editProperty(const char * /*propName*/) {}
@@ -249,11 +236,6 @@ public:
protected:
/** get called by the container when a property has changed
*
* This function is called before onChanged()
*/
virtual void onEarlyChange(const Property* /*prop*/){}
/// get called by the container when a property has changed
virtual void onChanged(const Property* /*prop*/){}
/// get called before the value is changed
@@ -274,12 +256,9 @@ private:
protected:
DynamicProperty dynamicProps;
private:
private:
std::string _propertyPrefix;
static PropertyData propertyData;
mutable std::unique_ptr<PropertyContainerP> _pimpl;
static PropertyData propertyData;
};
/// Property define
+2 -2
View File
@@ -23,8 +23,8 @@
#ifndef EXPRESSIONENGINE_H
#define EXPRESSIONENGINE_H
#include <functional>
#include <boost/unordered/unordered_map.hpp>
#include <boost/function.hpp>
#include <boost_signals2.hpp>
#include <boost_graph_adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
@@ -77,7 +77,7 @@ public:
virtual Property *CopyOnLinkReplace(const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const override;
typedef std::function<std::string (const App::ObjectIdentifier & path, std::shared_ptr<const App::Expression> expr)> ValidatorFunc;
typedef boost::function<std::string (const App::ObjectIdentifier & path, std::shared_ptr<const App::Expression> expr)> ValidatorFunc;
/**
* @brief The ExpressionInfo struct encapsulates an expression.
+18 -9
View File
@@ -354,17 +354,19 @@ void PropertyFileIncluded::Save (Base::Writer &writer) const
_cValue = fi.filePath();
}
if (writer.isForceXML()>3) {
if (writer.isForceXML()) {
if (!_cValue.empty()) {
Base::FileInfo file(_cValue.c_str());
writer.Stream() << writer.ind() << "<FileIncluded data=\""
<< encodeAttribute(file.fileName()) << "\">\n";
<< file.fileName() << "\">" << std::endl;
// write the file in the XML stream
writer.incInd();
writer.insertBinFile(_cValue.c_str());
writer.Stream() << writer.ind() <<"</FileIncluded>\n";
writer.decInd();
writer.Stream() << writer.ind() <<"</FileIncluded>" << endl;
}
else {
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>\n";
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>" << std::endl;
}
}
else {
@@ -404,7 +406,7 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
// is in the document transient path
aboutToSetValue();
_cValue = getDocTransientPath() + "/" + file;
reader.readCharacters(_cValue.c_str(),true);
reader.readBinFile(_cValue.c_str());
reader.readEndElement("FileIncluded");
_BaseFileName = file;
// set read-only after restoring the file
@@ -425,7 +427,12 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
throw Base::FileSystemError(str.str());
}
writer.Stream() << from.rdbuf();
// copy plain data
unsigned char c;
std::ostream& to = writer.Stream();
while (from.get((char&)c)) {
to.put((char)c);
}
}
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
@@ -436,7 +443,7 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
// same file of another object (e.g. for copy&paste of objects inside the same document).
return;
}
Base::ofstream to(fi, std::ios::out | std::ios::binary | std::ios::trunc);
Base::ofstream to(fi, std::ios::out | std::ios::binary);
if (!to) {
std::stringstream str;
str << "PropertyFileIncluded::RestoreDocFile(): "
@@ -446,8 +453,10 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
// copy plain data
aboutToSetValue();
reader >> to.rdbuf();
unsigned char c;
while (reader.get((char&)c)) {
to.put((char)c);
}
to.close();
// set read-only after restoring the file
+2 -58
View File
@@ -23,30 +23,19 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <assert.h>
#endif
#include <boost/algorithm/string/predicate.hpp>
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Exception.h>
#include <Base/MatrixPy.h>
#include <Base/Reader.h>
#include <Base/PlacementPy.h>
#include <Base/Reader.h>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <Base/Rotation.h>
#include <Base/RotationPy.h>
#include <Base/Stream.h>
#include <Base/Tools.h>
#include <Base/Writer.h>
#include <Base/VectorPy.h>
#include <Base/Writer.h>
#include "Document.h"
#include "DocumentObject.h"
#include "PropertyGeo.h"
#include "Placement.h"
#include "ObjectIdentifier.h"
@@ -1147,48 +1136,3 @@ PropertyComplexGeoData::~PropertyComplexGeoData()
{
}
std::string PropertyComplexGeoData::getElementMapVersion(bool) const {
auto data = getComplexData();
if(!data)
return std::string();
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
std::ostringstream ss;
if(owner && owner->getDocument()
&& owner->getDocument()->getStringHasher()==data->Hasher)
ss << "1.";
else
ss << "0.";
ss << data->getElementMapVersion();
return ss.str();
}
bool PropertyComplexGeoData::checkElementMapVersion(const char * ver) const
{
auto data = getComplexData();
if(!data)
return false;
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
std::ostringstream ss;
const char *prefix;
if(owner && owner->getDocument()
&& owner->getDocument()->getStringHasher() == data->Hasher)
prefix = "1.";
else
prefix = "0.";
if (!boost::starts_with(ver, prefix))
return true;
return data->checkElementMapVersion(ver+2);
}
void PropertyComplexGeoData::afterRestore()
{
auto data = getComplexData();
if (data && data->isRestoreFailed()) {
data->resetRestoreFailure();
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
if (owner && owner->getDocument() && !owner->getDocument()->testStatus(App::Document::PartialDoc))
owner->getDocument()->addRecomputeObject(owner);
}
PropertyGeometry::afterRestore();
}
-16
View File
@@ -508,10 +508,6 @@ public:
/** @name Modification */
//@{
/// Set the placement of the geometry
virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
/// Get the placement of the geometry
virtual Base::Matrix4D getTransform() const = 0;
/// Applies a transformation on the real geometric data type
virtual void transformGeometry(const Base::Matrix4D &rclMat) = 0;
/// Retrieve bounding box information
@@ -541,18 +537,6 @@ public:
virtual const Data::ComplexGeoData* getComplexData() const = 0;
virtual Base::BoundBox3d getBoundingBox() const = 0;
//@}
/** Return the element map version
*
* @param persisted: if true, return the restored element map version. Or
* else, return the current element map version
*/
virtual std::string getElementMapVersion(bool restored=false) const;
/// Return true to signal element map version change
virtual bool checkElementMapVersion(const char * ver) const;
virtual void afterRestore();
};
} // namespace App
+117 -353
View File
@@ -26,28 +26,22 @@
#include <QDir>
#include <QFileInfo>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost_bind_bind.hpp>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Tools.h>
#include "PropertyLinks.h"
#include "Application.h"
#include "Document.h"
#include "DocumentObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObserver.h"
#include "GeoFeature.h"
#include "ObjectIdentifier.h"
FC_LOG_LEVEL_INIT("App",true,true)
FC_LOG_LEVEL_INIT("PropertyLinks",true,true)
using namespace App;
using namespace Base;
@@ -62,9 +56,6 @@ namespace bp = boost::placeholders;
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLinkBase , App::Property)
static std::unordered_map<std::string, std::set<PropertyLinkBase*> > _LabelMap;
static std::unordered_map<App::DocumentObject *, std::unordered_set<PropertyLinkBase*> > _ElementRefMap;
PropertyLinkBase::PropertyLinkBase()
{}
@@ -77,11 +68,6 @@ void PropertyLinkBase::setAllowExternal(bool allow) {
setFlag(LinkAllowExternal,allow);
}
void PropertyLinkBase::setReturnNewElement(bool enable)
{
setFlag(LinkNewElement, enable);
}
void PropertyLinkBase::hasSetValue() {
auto owner = dynamic_cast<DocumentObject*>(getContainer());
if(owner)
@@ -113,15 +99,6 @@ bool PropertyLinkBase::isSame(const Property &other) const
}
void PropertyLinkBase::unregisterElementReference() {
for(auto obj : _ElementRefs) {
auto it = _ElementRefMap.find(obj);
if(it != _ElementRefMap.end()) {
it->second.erase(this);
if(it->second.empty())
_ElementRefMap.erase(it);
}
}
_ElementRefs.clear();
}
void PropertyLinkBase::unregisterLabelReferences()
@@ -226,76 +203,39 @@ static std::string propertyName(const Property *prop) {
return prop->getFullName();
}
std::vector<App::SubObjectT>
PropertyLinkBase::linkedElementsT(bool all) const
{
std::vector<App::DocumentObject*> objs;
std::vector<std::string> subs;
getLinks(objs,all,&subs,true);
std::vector<App::SubObjectT> res;
res.reserve(objs.size());
assert(objs.size() == subs.size());
for (unsigned i=0; i<objs.size(); ++i)
res.emplace_back(objs[i], subs[i].c_str());
return res;
}
const std::unordered_set<PropertyLinkBase*>&
PropertyLinkBase::getElementReferences(DocumentObject *feature)
{
static std::unordered_set<PropertyLinkBase*> none;
auto it = _ElementRefMap.find(feature);
if(it == _ElementRefMap.end())
return none;
return it->second;
}
void PropertyLinkBase::updateElementReferences(DocumentObject *feature, bool reverse) {
if(!feature || !feature->getNameInDocument())
return;
auto it = _ElementRefMap.find(feature);
if(it == _ElementRefMap.end())
return;
std::vector<PropertyLinkBase*> props;
props.reserve(it->second.size());
props.insert(props.end(),it->second.begin(),it->second.end());
for(auto prop : props) {
if(prop->getContainer()) {
try {
prop->updateElementReference(feature,reverse,true);
}catch(Base::Exception &e) {
e.ReportException();
FC_ERR("Failed to update element reference of " << propertyName(prop));
}catch(std::exception &e) {
FC_ERR("Failed to update element reference of " << propertyName(prop)
<< ": " << e.what());
}
}
}
(void)feature;
(void)reverse;
}
void PropertyLinkBase::_registerElementReference(App::DocumentObject *obj, std::string &sub, ShadowSub &shadow)
{
if(!obj || !obj->getNameInDocument() || sub.empty())
return;
if(shadow.first.empty()) {
_updateElementReference(0,obj,sub,shadow,false);
return;
}
GeoFeature *geo = 0;
const char *element = 0;
std::pair<std::string, std::string> elementName;
GeoFeature::resolveElement(obj,sub.c_str(), elementName,true,
GeoFeature::ElementNameType::Export,0,&element,&geo);
if(!geo || !element || !element[0])
return;
if(_ElementRefs.insert(geo).second)
_ElementRefMap[geo].insert(this);
(void)obj;
(void)sub;
(void)shadow;
}
class StringGuard {
public:
StringGuard(char *c)
:c(c)
{
v1 = c[0];
v2 = c[1];
c[0] = '.';
c[1] = 0;
}
~StringGuard()
{
c[0] = v1;
c[1] = v2;
}
char *c;
char v1;
char v2;
};
void PropertyLinkBase::restoreLabelReference(const DocumentObject *obj,
std::string &subname, ShadowSub *shadow)
{
@@ -337,139 +277,12 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
App::DocumentObject *obj, std::string &sub, ShadowSub &shadow,
bool reverse, bool notify)
{
if(!obj || !obj->getNameInDocument()) return false;
ShadowSub elementName;
const char *subname;
if(shadow.first.size())
subname = shadow.first.c_str();
else if(shadow.second.size())
subname = shadow.second.c_str();
else
subname = sub.c_str();
GeoFeature *geo = 0;
const char *element=0;
auto ret = GeoFeature::resolveElement(obj,subname, elementName,true,
GeoFeature::ElementNameType::Export,feature,&element,&geo);
if(!ret || !geo || !element || !element[0]) {
if(elementName.second.size())
shadow.second.swap(elementName.second);
return false;
}
if(_ElementRefs.insert(geo).second)
_ElementRefMap[geo].insert(this);
if (!reverse) {
if (elementName.first.empty()) {
shadow.second.swap(elementName.second);
return false;
}
if(shadow==elementName)
return false;
}
bool missing = GeoFeature::hasMissingElement(elementName.second.c_str());
if (feature == geo && (missing || reverse)) {
// If the referenced element is missing, or we are generating element
// map for the first time, or we are re-generating the element map due
// to version change, i.e. 'reverse', try search by geometry first
const char *oldElement = Data::ComplexGeoData::findElementName(shadow.second.c_str());
if(!Data::ComplexGeoData::hasMissingElement(oldElement)) {
const auto &names = geo->searchElementCache(oldElement);
if(names.size()) {
missing = false;
std::string newsub(subname, strlen(subname) - strlen(element));
newsub += names.front();
GeoFeature::resolveElement(obj, newsub.c_str(), elementName,true,
GeoFeature::ElementNameType::Export,feature);
const auto &oldSub = shadow.first.size()?shadow.first:shadow.second;
const auto &newSub = elementName.first.size()?elementName.first:elementName.second;
if (oldSub != newSub) {
FC_WARN(propertyName(this)
<< " auto change element reference " << ret->getFullName() << " "
<< oldSub << " -> " << newSub);
}
}
// Note: the following code proves to be too risky. There is no way
// (so far) to ensure the recompute do not change the geometry. If
// the geometry does remain the same, the above geometry search
// should be able to find the new reference any way!
#if 0
else if (missing && reverse && shadow.first.size()) {
// reverse means we are trying to either generate the element
// name for the first time, or upgrade to a new map version. In
// case of upgrading, we still consult the original mapped name
// in first try. Here means the first try failed, and the
// geometry search cannot find any match, so we try the
// non-mapped name as a last resort.
//
// WARNING! We are assuming the recomputation is done with no
// actual property change, and the resulting geometry remains
// the same. If this condition is not met, the result may be
// undesirable. TODO: find a way to ensure this condition.
GeoFeature::resolveElement(obj, shadow.second.c_str(), elementName, true,
GeoFeature::ElementNameType::Export,feature);
if(!elementName.second.empty()) {
missing = Data::ComplexGeoData::hasMissingElement(elementName.second.c_str());
if (!missing) {
FC_WARN(propertyName(this)
<< " element reference changed " << ret->getFullName() << " "
<< shadow.first << " -> " << elementName.first);
}
}
}
#endif
}
}
if(notify)
aboutToSetValue();
if(missing) {
FC_WARN(propertyName(this)
<< " missing element reference " << ret->getFullName() << " "
<< (elementName.first.size()?elementName.first:elementName.second));
shadow.second.swap(elementName.second);
} else {
FC_TRACE(propertyName(this)
<< " element reference shadow update " << ret->getFullName() << " "
<< shadow.first << " -> " << elementName.first);
shadow.swap(elementName);
if(shadow.first.size() && Data::ComplexGeoData::hasMappedElementName(sub.c_str()))
sub = shadow.first;
}
if(reverse) {
if(shadow.first.size() && Data::ComplexGeoData::hasMappedElementName(sub.c_str()))
sub = shadow.first;
else
sub = shadow.second;
return true;
}
if (missing) {
if (sub != shadow.first)
sub = shadow.second;
return true;
}
auto pos2 = shadow.first.rfind('.');
if(pos2 == std::string::npos)
return true;
++pos2;
auto pos = sub.rfind('.');
if(pos == std::string::npos)
pos = 0;
else
++pos;
if(pos==pos2) {
if(sub.compare(pos,sub.size()-pos,&shadow.first[pos2])!=0) {
FC_LOG("element reference update " << sub << " -> " << shadow.first);
sub.replace(pos,sub.size()-pos,&shadow.first[pos2]);
}
} else if(sub!=shadow.second) {
FC_LOG("element reference update " << sub << " -> " << shadow.second);
sub = shadow.second;
}
return true;
(void)feature;
(void)obj;
(void)reverse;
(void)notify;
shadow.second = sub;
return false;
}
std::pair<DocumentObject*, std::string>
@@ -478,8 +291,6 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
{
std::pair<DocumentObject*, std::string> res;
res.first = 0;
if (!obj)
return res;
if(oldObj == obj) {
if(owner == parent) {
@@ -499,11 +310,6 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
return res;
}
return res;
} else if (newObj == obj) {
// This means the new object is already sub-object of this parent
// (consider a case of swapping the tool and base object of the Cut
// feature). We'll swap the old and new object.
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
}
if(!subname || !subname[0])
return res;
@@ -514,8 +320,6 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
for(auto pos=sub.find('.');pos!=std::string::npos;pos=sub.find('.',pos)) {
++pos;
char c = sub[pos];
if (c == '.')
continue;
sub[pos] = 0;
auto sobj = obj->getSubObject(sub.c_str());
sub[pos] = c;
@@ -540,8 +344,6 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
return res;
}
break;
}else if(sobj == newObj) {
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
}else if(prev == parent)
break;
prev = sobj;
@@ -557,8 +359,6 @@ PropertyLinkBase::tryReplaceLinkSubs(const PropertyContainer *owner,
{
std::pair<DocumentObject*,std::vector<std::string> > res;
res.first = 0;
if (!obj)
return res;
auto r = tryReplaceLink(owner,obj,parent,oldObj,newObj);
if(r.first) {
@@ -1118,7 +918,7 @@ TYPESYSTEM_SOURCE(App::PropertyLinkSubHidden, App::PropertyLinkSub)
PropertyLinkSub::PropertyLinkSub()
: _pcLinkSub(nullptr)
: _pcLinkSub(nullptr), _restoreLabel(false)
{
}
@@ -1175,10 +975,9 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
#endif
_pcLinkSub=lValue;
_cSubList=std::move(subs);
if(shadows.size()==_cSubList.size()) {
if(shadows.size()==_cSubList.size())
_ShadowSubList = std::move(shadows);
onContainerRestored(); // re-register element references
} else
else
updateElementReference(nullptr);
checkLabelReferences(_cSubList);
hasSetValue();
@@ -1195,22 +994,13 @@ const std::vector<std::string>& PropertyLinkSub::getSubValues(void) const
}
static inline const std::string &getSubNameWithStyle(const std::string &subName,
const PropertyLinkBase::ShadowSub &shadow, bool newStyle, std::string &tmp)
const PropertyLinkBase::ShadowSub &shadow, bool newStyle)
{
if(!newStyle) {
if(shadow.second.size())
return shadow.second;
}else if(shadow.first.size()) {
if (Data::ComplexGeoData::hasMissingElement(shadow.second.c_str())) {
auto pos = shadow.first.rfind('.');
if (pos != std::string::npos) {
tmp = shadow.first.substr(0, pos+1);
tmp += shadow.second;
return tmp;
}
}
}else if(shadow.first.size())
return shadow.first;
}
return subName;
}
@@ -1218,24 +1008,20 @@ std::vector<std::string> PropertyLinkSub::getSubValues(bool newStyle) const {
assert(_cSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_cSubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp));
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle));
return ret;
}
std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* starter, bool newStyle) const
{
assert(_cSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i) {
const auto &sub = getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp);
auto element = Data::ComplexGeoData::findElementName(sub.c_str());
if(element && boost::starts_with(element,starter))
ret.emplace_back(element);
}
return ret;
(void)newStyle;
std::vector<std::string> temp;
for(std::vector<std::string>::const_iterator it=_cSubList.begin();it!=_cSubList.end();++it)
if(strncmp(starter,it->c_str(),strlen(starter))==0)
temp.push_back(*it);
return temp;
}
App::DocumentObject * PropertyLinkSub::getValue(Base::Type t) const
@@ -1250,9 +1036,8 @@ PyObject *PropertyLinkSub::getPyObject(void)
if (_pcLinkSub) {
_pcLinkSub->getPyObject();
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
int i = 0;
for (auto &sub : getSubValues(testFlag(LinkNewElement)))
list[i++] = Py::String(sub);
for(unsigned int i = 0;i<_cSubList.size(); i++)
list[i] = Py::String(_cSubList[i]);
tup[1] = list;
return Py::new_reference_to(tup);
}
@@ -1525,9 +1310,12 @@ std::string PropertyLinkBase::tryImportSubName(const App::DocumentObject *obj, c
return std::string();
}
static const char *AttrShadowed = "shadowed";
static const char *AttrShadow = "shadow";
static const char *AttrMapped = "mapped";
#define ATTR_SHADOWED "shadowed"
#define ATTR_SHADOW "shadow"
#define ATTR_MAPPED "mapped"
// We do not have topo naming yet, ignore shadow sub for now
#define IGNORE_SHADOW true
void PropertyLinkSub::Save (Base::Writer &writer) const
{
@@ -1540,7 +1328,7 @@ void PropertyLinkSub::Save (Base::Writer &writer) const
internal_name = _pcLinkSub->getExportName();
writer.Stream() << writer.ind() << "<LinkSub value=\""
<< internal_name <<"\" count=\"" << _cSubList.size();
writer.Stream() << "\">\n";
writer.Stream() << "\">" << std::endl;
writer.incInd();
auto owner = dynamic_cast<DocumentObject*>(getContainer());
bool exporting = owner && owner->isExporting();
@@ -1555,18 +1343,18 @@ void PropertyLinkSub::Save (Base::Writer &writer) const
std::string exportName;
writer.Stream() << encodeAttribute(exportSubName(exportName,_pcLinkSub,sub.c_str()));
if(shadow.second.size() && shadow.first == _cSubList[i])
writer.Stream() << "\" " << AttrMapped << "=\"1";
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
} else {
writer.Stream() << encodeAttribute(sub);
if(_cSubList[i].size()) {
if(sub!=_cSubList[i]) {
// Stores the actual value that is shadowed. For new version FC,
// we will restore this shadowed value instead.
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_cSubList[i]);
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_cSubList[i]);
}else if(shadow.first.size()){
// Here means the user set value is old style element name.
// We shall then store the shadow somewhere else.
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
}
}
}
@@ -1607,15 +1395,15 @@ void PropertyLinkSub::Restore(Base::XMLReader &reader)
for (int i = 0; i < count; i++) {
reader.readElement("Sub");
shadows[i].second = importSubName(reader,reader.getAttribute("value"),restoreLabel);
if(reader.hasAttribute(AttrShadowed)) {
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW) {
values[i] = shadows[i].first =
importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
} else {
values[i] = shadows[i].second;
if(reader.hasAttribute(AttrShadow))
shadows[i].first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
shadows[i].first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
}
if(reader.hasAttribute(AttrMapped))
if(reader.hasAttribute(ATTR_MAPPED))
mapped.push_back(i);
}
setFlag(LinkRestoreLabel,restoreLabel);
@@ -1715,7 +1503,6 @@ Property *PropertyLinkSub::Copy(void) const
PropertyLinkSub *p= new PropertyLinkSub();
p->_pcLinkSub = _pcLinkSub;
p->_cSubList = _cSubList;
p->_ShadowSubList = _ShadowSubList;
return p;
}
@@ -1986,10 +1773,9 @@ void PropertyLinkSubList::setValues(std::vector<DocumentObject*>&& lValue,
aboutToSetValue();
_lValueList = std::move(lValue);
_lSubList = std::move(lSubNames);
if(ShadowSubList.size()==_lSubList.size()) {
if(ShadowSubList.size()==_lSubList.size())
_ShadowSubList = std::move(ShadowSubList);
onContainerRestored(); // re-register element references
} else
else
updateElementReference(nullptr);
checkLabelReferences(_lSubList);
hasSetValue();
@@ -2214,7 +2000,7 @@ std::vector<PropertyLinkSubList::SubSet> PropertyLinkSubList::getSubListValues(b
PyObject *PropertyLinkSubList::getPyObject(void)
{
#if 1
std::vector<SubSet> subLists = getSubListValues(testFlag(LinkNewElement));
std::vector<SubSet> subLists = getSubListValues();
std::size_t count = subLists.size();
#if 0//FIXME: Should switch to tuple
Py::Tuple sequence(count);
@@ -2405,18 +2191,18 @@ void PropertyLinkSubList::Save (Base::Writer &writer) const
std::string exportName;
writer.Stream() << encodeAttribute(exportSubName(exportName,obj,sub.c_str()));
if(shadow.second.size() && _lSubList[i]==shadow.first)
writer.Stream() << "\" " << AttrMapped << "=\"1";
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
} else {
writer.Stream() << encodeAttribute(sub);
if(_lSubList[i].size()) {
if(sub!=_lSubList[i]) {
// Stores the actual value that is shadowed. For new version FC,
// we will restore this shadowed value instead.
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_lSubList[i]);
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_lSubList[i]);
}else if(shadow.first.size()) {
// Here means the user set value is old style element name.
// We shall then store the shadow somewhere else.
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
}
}
}
@@ -2457,15 +2243,15 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader)
shadows.emplace_back();
auto &shadow = shadows.back();
shadow.second = importSubName(reader,reader.getAttribute("sub"),restoreLabel);
if(reader.hasAttribute(AttrShadowed)) {
shadow.first = importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW) {
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
SubNames.push_back(shadow.first);
}else{
SubNames.push_back(shadow.second);
if(reader.hasAttribute(AttrShadow))
shadow.first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
}
if(reader.hasAttribute(AttrMapped))
if(reader.hasAttribute(ATTR_MAPPED))
mapped.push_back(i);
} else if (reader.isVerbose())
Base::Console().Warning("Lost link to '%s' while loading, maybe "
@@ -2476,7 +2262,7 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader)
reader.readEndElement("LinkSubList");
// assignment
setValues(values,std::move(SubNames),std::move(shadows));
setValues(values,SubNames,std::move(shadows));
_mapped.swap(mapped);
}
@@ -2665,7 +2451,6 @@ Property *PropertyLinkSubList::Copy(void) const
PropertyLinkSubList *p = new PropertyLinkSubList();
p->_lValueList = _lValueList;
p->_lSubList = _lSubList;
p->_ShadowSubList = _ShadowSubList;
return p;
}
@@ -2689,9 +2474,8 @@ std::vector<std::string> PropertyLinkSubList::getSubValues(bool newStyle) const
assert(_lSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_ShadowSubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle,tmp));
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle));
return ret;
}
@@ -2844,7 +2628,7 @@ public:
App::Document *pDoc,PropertyXLink *l, const char *objName)
{
QString path;
l->filePath = getDocPath(filename,pDoc,false,&path);
l->filePath = getDocPath(filename,pDoc,true,&path);
FC_LOG("finding doc " << filename);
@@ -3195,7 +2979,6 @@ PropertyXLink::PropertyXLink(bool _allowPartial, PropertyLinkBase *parent)
setAllowPartial(_allowPartial);
setAllowExternal(true);
setSyncSubObject(true);
// setReturnNewElement(true);
if(parent)
setContainer(parent->getContainer());
}
@@ -3227,27 +3010,18 @@ void PropertyXLink::detach() {
}
}
std::string PropertyXLink::getFullName(bool python) const {
if((getName() && getName()[0]) || python || !parentProp)
return inherited::getFullName(python);
std::ostringstream ss;
ss << parentProp->getFullName() << ":" << this;
return ss.str();
}
void PropertyXLink::aboutToSetValue() {
if(parentProp)
parentProp->aboutToSetChildValue(*this);
else
inherited::aboutToSetValue();
PropertyLinkBase::aboutToSetValue();
}
void PropertyXLink::hasSetValue() {
if(parentProp)
parentProp->hasSetChildValue(*this);
else
inherited::hasSetValue();
PropertyLinkBase::hasSetValue();
}
void PropertyXLink::setSubName(const char *subname)
@@ -3261,14 +3035,13 @@ void PropertyXLink::setSubName(const char *subname)
}
void PropertyXLink::setSubValues(std::vector<std::string> &&subs,
std::vector<ShadowSub> &&shadows)
std::vector<ShadowSub> &&shadows)
{
_SubList = std::move(subs);
_ShadowSubList.clear();
if(shadows.size() == _SubList.size()) {
if(shadows.size() == _SubList.size())
_ShadowSubList = std::move(shadows);
onContainerRestored(); // re-register element references
} else
else
updateElementReference(nullptr);
checkLabelReferences(_SubList);
}
@@ -3557,11 +3330,9 @@ void PropertyXLink::Save (Base::Writer &writer) const {
}else
FC_WARN("PropertyXLink export without saving the document");
}
} else if (filePath.size())
_path = DocInfo::getDocPath(filePath.c_str(),owner->getDocument(),true);
if(_path.size())
path = _path.c_str();
if(_path.size())
path = _path.c_str();
}
writer.Stream() << writer.ind()
<< "<XLink file=\"" << encodeAttribute(path)
<< "\" stamp=\"" << (docInfo&&docInfo->pcDoc?docInfo->pcDoc->LastModifiedDate.getValue():"")
@@ -3582,14 +3353,14 @@ void PropertyXLink::Save (Base::Writer &writer) const {
writer.Stream() << "\" sub=\"" <<
encodeAttribute(exportSubName(exportName,_pcLink,sub.c_str()));
if(shadowSub.second.size() && shadowSub.first==subName)
writer.Stream() << "\" " << AttrMapped << "=\"1";
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
}else{
writer.Stream() << "\" sub=\"" << encodeAttribute(sub);
if(sub.size()) {
if(sub!=subName)
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(subName);
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(subName);
else if(shadowSub.first.size())
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadowSub.first);
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadowSub.first);
}
}
writer.Stream() << "\"/>" << std::endl;
@@ -3607,14 +3378,14 @@ void PropertyXLink::Save (Base::Writer &writer) const {
std::string exportName;
writer.Stream() << encodeAttribute(exportSubName(exportName,_pcLink,sub.c_str()));
if(shadow.second.size() && shadow.first == _SubList[i])
writer.Stream() << "\" " << AttrMapped << "=\"1";
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
} else {
writer.Stream() << encodeAttribute(sub);
if(_SubList[i].size()) {
if(sub!=_SubList[i])
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_SubList[i]);
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_SubList[i]);
else if(shadow.first.size())
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
}
}
writer.Stream()<<"\"/>" << endl;
@@ -3661,19 +3432,19 @@ void PropertyXLink::Restore(Base::XMLReader &reader)
std::vector<int> mapped;
bool restoreLabel = false;
if(reader.hasAttribute("sub")) {
if(reader.hasAttribute(AttrMapped))
if(reader.hasAttribute(ATTR_MAPPED))
mapped.push_back(0);
subs.emplace_back();
auto &subname = subs.back();
shadows.emplace_back();
auto &shadow = shadows.back();
shadow.second = importSubName(reader,reader.getAttribute("sub"),restoreLabel);
if(reader.hasAttribute(AttrShadowed))
subname = shadow.first = importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW)
subname = shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
else {
subname = shadow.second;
if(reader.hasAttribute(AttrShadow))
shadow.first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
}
}else if(reader.hasAttribute("count")) {
int count = reader.getAttributeAsInteger("count");
@@ -3682,15 +3453,15 @@ void PropertyXLink::Restore(Base::XMLReader &reader)
for (int i = 0; i < count; i++) {
reader.readElement("Sub");
shadows[i].second = importSubName(reader,reader.getAttribute("value"),restoreLabel);
if(reader.hasAttribute(AttrShadowed))
subs[i] = shadows[i].first =
importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW)
subs[i] = shadows[i].first =
importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
else {
subs[i] = shadows[i].second;
if(reader.hasAttribute(AttrShadow))
shadows[i].first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
shadows[i].first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
}
if(reader.hasAttribute(AttrMapped))
if(reader.hasAttribute(ATTR_MAPPED))
mapped.push_back(i);
}
reader.readEndElement("XLink");
@@ -3771,10 +3542,8 @@ void PropertyXLink::copyTo(PropertyXLink &other,
}
if(subs)
other._SubList = std::move(*subs);
else {
else
other._SubList = _SubList;
other._ShadowSubList = _ShadowSubList;
}
other._Flags = _Flags;
}
@@ -3893,7 +3662,7 @@ PyObject *PropertyXLink::getPyObject(void)
{
if(!_pcLink)
Py_Return;
const auto &subs = getSubValues(testFlag(LinkNewElement));
const auto &subs = getSubValues(false);
if(subs.empty())
return _pcLink->getPyObject();
Py::Tuple ret(2);
@@ -3957,7 +3726,7 @@ void PropertyXLink::setPyObject(PyObject *value) {
const char *PropertyXLink::getSubName(bool newStyle) const {
if(_SubList.empty() || _ShadowSubList.empty())
return "";
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle,tmpShadow).c_str();
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle).c_str();
}
void PropertyXLink::getLinks(std::vector<App::DocumentObject *> &objs,
@@ -3988,24 +3757,20 @@ std::vector<std::string> PropertyXLink::getSubValues(bool newStyle) const {
assert(_SubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_SubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp));
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle));
return ret;
}
std::vector<std::string> PropertyXLink::getSubValuesStartsWith(const char* starter, bool newStyle) const
{
assert(_SubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i) {
const auto &sub = getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp);
auto element = Data::ComplexGeoData::findElementName(sub.c_str());
if(element && boost::starts_with(element,starter))
ret.emplace_back(element);
}
return ret;
(void)newStyle;
std::vector<std::string> temp;
for(std::vector<std::string>::const_iterator it=_SubList.begin();it!=_SubList.end();++it)
if(strncmp(starter,it->c_str(),strlen(starter))==0)
temp.push_back(*it);
return temp;
}
void PropertyXLink::setAllowPartial(bool enable) {
@@ -4061,7 +3826,7 @@ PyObject *PropertyXLinkSub::getPyObject(void)
Py_Return;
Py::Tuple ret(2);
ret.setItem(0,Py::Object(_pcLink->getPyObject(),true));
const auto &subs = getSubValues(testFlag(LinkNewElement));
const auto &subs = getSubValues(false);
Py::List list(subs.size());
int i = 0;
PropertyString propString;
@@ -4087,7 +3852,6 @@ PropertyXLinkSubList::PropertyXLinkSubList()
{
_pcScope = LinkScope::Global;
setSyncSubObject(true);
// setReturnNewElement(true);
}
PropertyXLinkSubList::~PropertyXLinkSubList()
@@ -4323,7 +4087,7 @@ PyObject *PropertyXLinkSubList::getPyObject(void)
Py::Tuple tup(2);
tup[0] = Py::asObject(obj->getPyObject());
const auto &subs = link.getSubValues(testFlag(LinkNewElement));
const auto &subs = link.getSubValues();
Py::Tuple items(subs.size());
for (std::size_t j = 0; j < subs.size(); j++) {
items[j] = Py::String(subs[j]);
@@ -4343,7 +4107,7 @@ void PropertyXLinkSubList::setPyObject(PyObject *value)
this->setValue(dummy.getValue(), dummy.getSubValues());
return;
}
catch (Base::TypeError&) {}
catch (Base::Exception&) {}
if (!PyTuple_Check(value) && !PyList_Check(value))
throw Base::TypeError("Invalid type. Accepts (DocumentObject, (subname...)) or sequence of such type.");
+4 -19
View File
@@ -26,11 +26,8 @@
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include "Property.h"
namespace Base {
@@ -41,8 +38,6 @@ namespace App
{
class DocumentObject;
class Document;
class GeoFeature;
class SubObjectT;
class DocInfo;
typedef std::shared_ptr<DocInfo> DocInfoPtr;
@@ -259,7 +254,7 @@ public:
/// Helper function to return linked objects using an std::inserter
template<class T>
void getLinkedObjects(T inserter, bool all=false) const {
void getLinkedObjects(T &inserter, bool all=false) const {
std::vector<App::DocumentObject*> ret;
getLinks(ret,all);
std::copy(ret.begin(),ret.end(),inserter);
@@ -267,7 +262,7 @@ public:
/// Helper function to return a map of linked object and its subname references
void getLinkedElements(std::map<App::DocumentObject*, std::vector<std::string> > &elements,
bool newStyle=true, bool all=false) const
bool newStyle=true, bool all=true) const
{
std::vector<App::DocumentObject*> ret;
std::vector<std::string> subs;
@@ -280,14 +275,12 @@ public:
/// Helper function to return a map of linked object and its subname references
std::map<App::DocumentObject*, std::vector<std::string> >
linkedElements(bool newStyle=true, bool all=false) const
linkedElements(bool newStyle=true, bool all=true) const
{
std::map<App::DocumentObject*, std::vector<std::string> > ret;
getLinkedElements(ret,newStyle,all);
return ret;
}
std::vector<App::SubObjectT> linkedElementsT(bool all) const;
//@}
virtual bool isSame(const Property &other) const override;
@@ -353,8 +346,6 @@ public:
/// Update all element references in all link properties of \a feature
static void updateElementReferences(DocumentObject *feature, bool reverse=false);
/// Obtain link properties that contain element references to a given object
static const std::unordered_set<PropertyLinkBase*>& getElementReferences(DocumentObject *);
/** Helper function for update individual element reference
*
@@ -547,7 +538,6 @@ public:
LinkAllowPartial,
LinkRestoreLabel,
LinkSyncSubObject, // used by DlgPropertyLink
LinkNewElement, // return new element name in getPyObject
};
inline bool testFlag(int flag) const {
return _Flags.test((std::size_t)flag);
@@ -555,8 +545,6 @@ public:
virtual void setAllowPartial(bool enable) { (void)enable; }
void setReturnNewElement(bool enable);
protected:
virtual void hasSetValue() override;
@@ -1064,7 +1052,6 @@ class PropertyXLinkSubList;
class AppExport PropertyXLink : public PropertyLinkGlobal
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
typedef PropertyLinkGlobal inherited;
public:
PropertyXLink(bool allowPartial=false, PropertyLinkBase *parent=nullptr);
@@ -1150,7 +1137,6 @@ public:
virtual void setAllowPartial(bool enable) override;
virtual std::string getFullName(bool python=false) const override;
const char *getFilePath() const {
return filePath.c_str();
}
@@ -1183,7 +1169,6 @@ protected:
std::vector<ShadowSub> _ShadowSubList;
std::vector<int> _mapped;
PropertyLinkBase *parentProp;
mutable std::string tmpShadow;
};
@@ -1213,10 +1198,10 @@ class AppExport PropertyXLinkSubList: public PropertyLinkBase
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
typedef typename AtomicPropertyChangeInterface<PropertyXLinkSubList>::AtomicPropertyChange atomic_change;
friend atomic_change;
public:
PropertyXLinkSubList();
virtual ~PropertyXLinkSubList();
+11 -10
View File
@@ -392,9 +392,9 @@ void PropertyEnumeration::setEnumVector(const std::vector<std::string> &values)
hasSetValue();
}
bool PropertyEnumeration::hasEnums() const
const char ** PropertyEnumeration::getEnums() const
{
return _enum.hasEnums();
return _enum.getEnums();
}
bool PropertyEnumeration::isValid() const
@@ -447,7 +447,7 @@ void PropertyEnumeration::Restore(Base::XMLReader &reader)
if (val < 0) {
// If the enum is empty at this stage do not print a warning
if (_enum.hasEnums())
if (_enum.getEnums())
Base::Console().Warning("Enumeration index %d is out of range, ignore it\n", val);
val = getValue();
}
@@ -598,13 +598,13 @@ bool PropertyEnumeration::getPyPathValue(const ObjectIdentifier &path, Py::Objec
if (p == ".Enum" || p == ".All") {
Base::PyGILStateLocker lock;
Py::Tuple res(_enum.maxValue()+1);
std::vector<std::string> enums = _enum.getEnumVector();
const char **enums = _enum.getEnums();
PropertyString tmp;
for(int i=0;i< int(enums.size());++i) {
for(int i=0;i<=_enum.maxValue();++i) {
tmp.setValue(enums[i]);
res.setItem(i,Py::asObject(tmp.getPyObject()));
}
if (p == ".Enum")
if(p == ".Enum")
r = res;
else {
Py::Tuple tuple(2);
@@ -1374,7 +1374,7 @@ PropertyString::~PropertyString()
void PropertyString::setValue(const char* newLabel)
{
if(!newLabel)
if(!newLabel)
return;
if(_cValue == newLabel)
@@ -2065,9 +2065,10 @@ PyObject *PropertyBool::getPyObject()
void PropertyBool::setPyObject(PyObject *value)
{
if (PyBool_Check(value) || PyLong_Check(value)) {
setValue(PyObject_IsTrue(value) ? true : false);
}
if (PyBool_Check(value))
setValue(PyObject_IsTrue(value)!=0);
else if(PyLong_Check(value))
setValue(PyLong_AsLong(value)!=0);
else {
std::string error = std::string("type must be bool, not ");
error += value->ob_type->tp_name;
+1 -1
View File
@@ -206,7 +206,7 @@ public:
/// set enum values as vector of strings
void setEnumVector(const std::vector<std::string> &);
/// get the pointer to the enum list
bool hasEnums() const;
const char ** getEnums(void) const;
/// Returns true if the instance is in a usable state
bool isValid(void) const;
+2 -2
View File
@@ -193,14 +193,14 @@ void PropertyQuantityConstraint::setPyObject(PyObject *value)
quant.setValue(temp);
if (unit.isEmpty()){
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
PropertyFloat::setValue(quant.getValue());
return;
}
if (unit != _Unit)
throw Base::UnitsMismatchError("Not matching Unit!");
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
PropertyFloat::setValue(quant.getValue());
}
//**************************************************************************
-749
View File
@@ -1,749 +0,0 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <deque>
#include <QCryptographicHash>
#include <QHash>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/iostreams/stream.hpp>
#include "StringHasher.h"
#include "StringHasherPy.h"
#include "DocumentParams.h"
#include "MappedElement.h"
#include "StringIDPy.h"
FC_LOG_LEVEL_INIT("App",true,true)
namespace bio = boost::iostreams;
using namespace App;
///////////////////////////////////////////////////////////
struct StringIDHasher {
std::size_t operator()(const StringID *sid) const {
if (!sid)
return 0;
return qHash(sid->data(), qHash(sid->postfix()));
}
bool operator()(const StringID *IDa, const StringID *IDb) const {
if (IDa == IDb)
return true;
if (!IDa || !IDb)
return false;
return IDa->data() == IDb->data() && IDa->postfix() == IDb->postfix();
}
};
typedef boost::bimap<
boost::bimaps::unordered_set_of<StringID *,
StringIDHasher,
StringIDHasher>,
boost::bimaps::set_of<long>>
HashMapBase;
class StringHasher::HashMap: public HashMapBase
{
public:
bool SaveAll = false;
int Threshold = 0;
};
///////////////////////////////////////////////////////////
TYPESYSTEM_SOURCE_ABSTRACT(App::StringID, Base::BaseClass)
StringID::~StringID()
{
if (_hasher)
_hasher->_hashes->right.erase(_id);
}
PyObject *StringID::getPyObject() {
return new StringIDPy(this);
}
PyObject *StringID::getPyObjectWithIndex(int index) {
auto res = new StringIDPy(this);
res->_index = index;
return res;
}
std::string StringID::toString(int index) const {
std::ostringstream ss;
ss << '#' << std::hex << value();
if (index)
ss << ':' << index;
return ss.str();
}
StringID::IndexID StringID::fromString(const char *name, bool eof, int size) {
IndexID res;
res.id = 0;
res.index = 0;
if (!name) {
res.id = -1;
return res;
}
if (size < 0)
size = std::strlen(name);
bio::stream<bio::array_source> iss(name, size);
char sep = 0;
char sep2 = 0;
iss >> sep >> std::hex >> res.id >> sep2 >> res.index;
if ((eof && !iss.eof()) || sep != '#' || (sep2 != 0 && sep2 != ':')) {
res.id = -1;
return res;
}
return res;
}
std::string StringID::dataToText(int index) const {
if(isHashed() || isBinary())
return _data.toBase64().constData();
std::string res(_data.constData());
if (index)
res += std::to_string(index);
if (_postfix.size())
res += _postfix.constData();
return res;
}
void StringID::mark() const
{
if (isMarked())
return;
_flags.setFlag(Flag::Marked);
for (auto &sid : _sids)
sid.deref().mark();
}
///////////////////////////////////////////////////////////
TYPESYSTEM_SOURCE(App::StringHasher, Base::Persistence)
StringHasher::StringHasher()
:_hashes(new HashMap)
{}
StringHasher::~StringHasher() {
clear();
}
void StringHasher::setSaveAll(bool enable) {
if (_hashes->SaveAll == enable)
return;
_hashes->SaveAll = enable;
compact();
}
void StringHasher::compact()
{
if (_hashes->SaveAll)
return;
std::deque<StringIDRef> pendings;
for (auto &v : _hashes->right) {
if (!v.second->isPersistent() && v.second->getRefCount() == 1)
pendings.emplace_back(v.second);
}
while (pendings.size()) {
StringIDRef sid = pendings.front();
pendings.pop_front();
if (!_hashes->right.erase(sid.value()))
continue;
sid._sid->_hasher = nullptr;
sid._sid->unref();
for (auto &s : sid._sid->_sids) {
if (s._sid->_hasher == this
&& !s._sid->isPersistent()
&& s._sid->getRefCount() == 2)
pendings.push_back(s);
}
}
}
bool StringHasher::getSaveAll() const {
return _hashes->SaveAll;
}
void StringHasher::setThreshold(int threshold) {
_hashes->Threshold = threshold;
}
int StringHasher::getThreshold() const {
return _hashes->Threshold;
}
long StringHasher::lastID() const {
if(_hashes->right.empty())
return 0;
auto it = _hashes->right.end();
--it;
return it->first;
}
StringIDRef StringHasher::getID(const char *text, int len, bool hashable) {
if (len < 0)
len = strlen(text);
return getID(QByteArray::fromRawData(text, len), hashable ? Option::Hashable : Option::None);
}
StringIDRef StringHasher::getID(const QByteArray &data, Options options)
{
bool binary = options.testFlag(Option::Binary);
bool hashable = options.testFlag(Option::Hashable);
bool nocopy = options.testFlag(Option::NoCopy);
bool hashed = hashable && _hashes->Threshold > 0
&& (int)data.size() > _hashes->Threshold;
StringID dataID;
if (hashed) {
QCryptographicHash hasher(QCryptographicHash::Sha1);
hasher.addData(data);
dataID._data = hasher.result();
}
else
dataID._data = data;
auto it = _hashes->left.find(&dataID);
if (it != _hashes->left.end())
return StringIDRef(it->first);
if (!hashed && !nocopy)
// if not hashed, make a deep copy of the data
dataID._data = QByteArray(data.constData(), data.size());
StringID::Flags flags(StringID::Flag::None);
if (binary)
flags.setFlag(StringID::Flag::Binary);
if (hashed)
flags.setFlag(StringID::Flag::Hashed);
StringIDRef sid(new StringID(lastID() + 1, dataID._data, flags));
return StringIDRef(insert(sid));
}
StringIDRef StringHasher::getID(const Data::MappedName &name,
const QVector<StringIDRef> & sids)
{
StringID anID;
anID._postfix = name.postfixBytes();
Data::IndexedName indexed;
if (!anID._postfix.size())
indexed = Data::IndexedName(name.dataBytes());
if (indexed)
anID._data = QByteArray::fromRawData(indexed.getType(), strlen(indexed.getType()));
else
anID._data = name.dataBytes();
auto it = _hashes->left.find(&anID);
if (it != _hashes->left.end()) {
auto res = StringIDRef(it->first);
if (indexed)
res._index = indexed.getIndex();
return res;
}
if (!indexed && name.isRaw())
anID._data = QByteArray(name.dataBytes().constData(),
name.dataBytes().size());
StringIDRef postfixRef;
if (anID._postfix.size() && anID._postfix.indexOf("#") < 0) {
postfixRef = getID(anID._postfix);
postfixRef.toBytes(anID._postfix);
}
StringIDRef indexRef;
if (indexed)
indexRef = getID(anID._data);
StringIDRef sid(new StringID(lastID() + 1, anID._data));
StringID &id = *sid._sid;
if (anID._postfix.size()) {
id._flags.setFlag(StringID::Flag::Postfixed);
id._postfix = anID._postfix;
}
int count = 0;
for (auto &sid : sids) {
if (sid && sid._sid->_hasher == this)
++count;
}
int extra = (postfixRef ? 1 : 0) + (indexRef ? 1 : 0);
if (count == sids.size() && !postfixRef && !indexRef)
id._sids = sids;
else {
id._sids.reserve(count + extra);
if (postfixRef) {
id._flags.setFlag(StringID::Flag::PostfixEncoded);
id._sids.push_back(postfixRef);
}
if (indexRef) {
id._flags.setFlag(StringID::Flag::Indexed);
id._sids.push_back(indexRef);
}
for (auto &s : sids) {
if (s && s._sid->_hasher == this)
id._sids.push_back(s);
}
}
if (id._sids.size() > 10) {
std::sort(id._sids.begin() + extra, id._sids.end());
id._sids.erase(std::unique(id._sids.begin() + extra, id._sids.end()), id._sids.end());
}
if (id._postfix.size() && !indexed) {
StringID::IndexID res = StringID::fromString(id._data);
if (res.id > 0) {
int offset = id.isPostfixEncoded() ? 1 : 0;
for (int i = offset; i < id._sids.size(); ++i) {
if (id._sids[i].value() == res.id) {
if (i!=offset)
std::swap(id._sids[offset], id._sids[i]);
if (res.index != 0)
id._flags.setFlag(StringID::Flag::PrefixIDIndex);
else
id._flags.setFlag(StringID::Flag::PrefixID);
break;
}
}
}
}
return StringIDRef(insert(sid), indexed.getIndex());
}
StringIDRef StringHasher::getID(long id, int index) const {
if (id<=0)
return StringIDRef();
auto it = _hashes->right.find(id);
if (it == _hashes->right.end())
return StringIDRef();
StringIDRef res(it->second);
res._index = index;
return res;
}
void StringHasher::setPersistenceFileName(const char *filename) const {
if (!filename)
filename = "";
_filename = filename;
}
const std::string &StringHasher::getPersistenceFileName() const {
return _filename;
}
void StringHasher::Save(Base::Writer &writer) const {
size_t count;
if (_hashes->SaveAll)
count = _hashes->size();
else {
count = 0;
for (auto &v : _hashes->right) {
if (v.second->isMarked() || v.second->isPersistent())
++count;
}
}
writer.Stream() << writer.ind()
<< "<StringHasher saveall=\"" << _hashes->SaveAll
<< "\" threshold=\"" << _hashes->Threshold << "\"";
if (!count) {
writer.Stream() << " count=\"0\"></StringHasher>\n";
return;
}
writer.Stream() << " count=\"0\" new=\"1\"/>\n";
writer.Stream() << writer.ind() << "<StringHasher2 ";
if (_filename.size()) {
writer.Stream() << " file=\""
<< writer.addFile(_filename + ".txt", this)
<< "\"/>\n";
return;
}
writer.Stream() << " count=\"" << count << "\">\n";
saveStream(writer.beginCharStream(false) << '\n');
writer.endCharStream() << '\n';
writer.Stream() << writer.ind() << "</StringHasher2>\n";
}
void StringHasher::SaveDocFile(Base::Writer &writer) const {
std::size_t count = _hashes->SaveAll?this->size():this->count();
writer.Stream() << "StringTableStart v1 " << count << '\n';
saveStream(writer.Stream());
}
void StringHasher::saveStream(std::ostream &s) const {
Base::OutputStream str(s,false);
boost::io::ios_flags_saver ifs(s);
s << std::hex;
bool allowRealtive = DocumentParams::getRelativeStringID();
long anchor = 0;
const StringID *last = nullptr;
long lastid = 0;
bool relative = false;
for (auto &v : _hashes->right) {
auto &d = *v.second;
long id = d._id;
if (!_hashes->SaveAll && !d.isMarked() && !d.isPersistent())
continue;
if (!allowRealtive)
s << id;
else {
// We use relative coding to save space. But in order to have some
// minimum protection against corruption, write an absolute value every
// once a while.
relative = (id - anchor) < 1000;
if (relative)
s << '-' << id - lastid;
else {
anchor = id;
s << id;
}
lastid = id;
}
int offset = d.isPostfixEncoded() ? 1 : 0;
StringID::IndexID prefixid;
prefixid.id = 0;
prefixid.index = 0;
if (d.isPrefixID()) {
assert(d._sids.size() > offset);
prefixid.id = d._sids[offset].value();
}
else if (d.isPrefixIDIndex()) {
prefixid = StringID::fromString(d._data);
assert(d._sids.size() > offset && d._sids[offset].value() == prefixid.id);
}
auto flags = d._flags;
flags.setFlag(StringID::Flag::Marked, false);
s << '.' << flags.toUnderlyingType();
int i = 0;
if (!relative) {
for (; i < d._sids.size(); ++i)
s << '.' << d._sids[i].value();
}
else {
if (last) {
for (; i < d._sids.size() && i < last->_sids.size(); ++i) {
long m = last->_sids[i].value();
long n = d._sids[i].value();
if (n < m)
s << ".-" << m-n;
else
s << '.' << n - m;
}
}
for (; i < d._sids.size(); ++i)
s << '.' << id - d._sids[i].value();
}
last = &d;
// Having postfix means it is a geometry element name, which
// guarantees to be a single line without space. So it is safe to
// store in raw stream.
if (d.isPostfixed()) {
if (d.isPrefixIDIndex())
s << ' ' << prefixid.index;
else if (!d.isIndexed() && !d.isPrefixID())
s << ' ' << d._data.constData();
if (!d.isPostfixEncoded())
s << ' ' << d._postfix.constData();
s << '\n';
}
else {
// Reaching here means the string may contain space and newlines
// We rely on OutputStream (i.e. str) to save the string.
s << ' ';
str << d._data.constData();
}
}
}
void StringHasher::RestoreDocFile(Base::Reader &reader) {
std::string marker, ver;
reader >> marker;
std::size_t count;
_hashes->clear();
if (marker == "StringTableStart") {
reader >> ver >> count;
if (ver != "v1")
FC_WARN("Unknown string table format");
restoreStreamNew(reader, count);
return;
}
count = atoi(marker.c_str());
restoreStream(reader, count);
}
void StringHasher::restoreStreamNew(std::istream &s, std::size_t count) {
Base::InputStream str(s, false);
_hashes->clear();
std::string content;
boost::io::ios_flags_saver ifs(s);
s >> std::hex;
std::vector<std::string> tokens;
long lastid = 0;
const StringID *last = nullptr;
std::string tmp;
for (uint32_t i = 0; i < count; ++i) {
if (!(s >> tmp))
FC_THROWM(Base::RuntimeError, "Invalid string table");
tokens.clear();
boost::split(tokens, tmp, boost::is_any_of("."));
if (tokens.size() < 2)
FC_THROWM(Base::RuntimeError, "Invalid string table");
long id;
bool relative = false;
if (tokens[0][0] == '-') {
relative = true;
id = lastid + strtol(tokens[0].c_str() + 1, nullptr, 16);
}
else
id = strtol(tokens[0].c_str(), nullptr, 16);
lastid = id;
unsigned long flag = strtol(tokens[1].c_str(), nullptr, 16);
StringIDRef sid(new StringID(id, QByteArray(), static_cast<StringID::Flag>(flag)));
StringID &d = *sid._sid;
d._sids.reserve(tokens.size() - 2);
int j = 2;
if (relative && last) {
for (; j < (int)tokens.size() && j - 2 < last->_sids.size(); ++j) {
long m = last->_sids[j - 2].value();
long n;
if (tokens[j][0] == '-')
n = -strtol(&tokens[j][1], nullptr, 16);
else
n = strtol(&tokens[j][0], nullptr, 16);
StringIDRef sid = getID(m + n);
if (!sid)
FC_THROWM(Base::RuntimeError, "Invalid string id reference");
d._sids.push_back(sid);
}
}
for (; j < (int)tokens.size(); ++j) {
long n = strtol(&tokens[j][0], nullptr, 16);
StringIDRef sid = getID(relative ? id - n : n);
if (!sid)
FC_THROWM(Base::RuntimeError, "Invalid string id reference");
d._sids.push_back(sid);
}
if (!d.isPostfixed()) {
str >> content;
if (d.isHashed() || d.isBinary())
d._data = QByteArray::fromBase64(content.c_str());
else
d._data = content.c_str();
}
else {
int offset = 0;
if (d.isPostfixEncoded()) {
offset = 1;
if (d._sids.empty())
FC_THROWM(Base::RuntimeError, "Missing string postfix");
d._postfix = d._sids[0]._sid->_data;
}
if (d.isIndexed()) {
if (d._sids.size() <= offset)
FC_THROWM(Base::RuntimeError, "Missing string prefix");
d._data = d._sids[offset]._sid->_data;
}
else if (d.isPrefixID() || d.isPrefixIDIndex()) {
if (d._sids.size() <= offset)
FC_THROWM(Base::RuntimeError, "Missing string prefix id");
int index = 0;
if (d.isPrefixIDIndex()) {
if (!(s >> index))
FC_THROWM(Base::RuntimeError, "Missing string prefix index");
}
d._data = d._sids[offset]._sid->toString(index).c_str();
}
else {
s >> content;
d._data = content.c_str();
}
if (!d.isPostfixEncoded()) {
s >> content;
d._postfix = content.c_str();
}
}
last = insert(sid);
}
}
StringID *StringHasher::insert(const StringIDRef &sid)
{
assert(sid && sid._sid->_hasher == nullptr);
auto &d = *sid._sid;
d._hasher = this;
d.ref();
auto res = _hashes->right.insert(_hashes->right.end(),
HashMap::right_map::value_type(sid.value(), &d));
if (res->second != &d) {
d._hasher = nullptr;
d.unref();
}
return res->second;
}
void StringHasher::restoreStream(std::istream &s, std::size_t count) {
Base::InputStream str(s, false);
_hashes->clear();
std::string content;
for (uint32_t i = 0; i < count; ++i) {
int32_t id;
uint8_t type;
str >> id >> type >> content;
StringIDRef sid = new StringID(id, QByteArray(), static_cast<StringID::Flag>(type));
if (sid.isHashed() || sid.isBinary())
sid._sid->_data = QByteArray::fromBase64(content.c_str());
else
sid._sid->_data = QByteArray(content.c_str());
insert(sid);
}
}
void StringHasher::clear() {
for (auto & v : _hashes->right) {
v.second->_hasher = nullptr;
v.second->unref();
}
_hashes->clear();
}
size_t StringHasher::size() const {
return _hashes->size();
}
size_t StringHasher::count() const {
size_t count = 0;
for (auto &v : _hashes->right)
if (v.second->getRefCount() > 1)
++count;
return count;
}
void StringHasher::Restore(Base::XMLReader &reader) {
clear();
reader.readElement("StringHasher");
_hashes->SaveAll = reader.getAttributeAsInteger("saveall") ? true : false;
_hashes->Threshold = reader.getAttributeAsInteger("threshold");
bool newtag = false;
if (reader.getAttributeAsInteger("new", "0") > 0) {
reader.readElement("StringHasher2");
newtag = true;
}
if (reader.hasAttribute("file")) {
const char *file = reader.getAttribute("file");
if(*file)
reader.addFile(file, this);
return;
}
std::size_t count = reader.getAttributeAsUnsigned("count");
if (newtag) {
restoreStreamNew(reader.beginCharStream(false), count);
reader.readEndElement("StringHasher2");
return;
}
else if (count && reader.FileVersion > 1)
restoreStream(reader.beginCharStream(false), count);
else {
for (std::size_t i = 0; i < count; ++i) {
reader.readElement("Item");
StringIDRef sid;
long id = reader.getAttributeAsInteger("id");
bool hashed = reader.hasAttribute("hash");
if (hashed || reader.hasAttribute("data")) {
const char *value = hashed ? reader.getAttribute("hash") : reader.getAttribute("data");
sid = new StringID(id, QByteArray::fromBase64(value), StringID::Flag::Hashed);
}
else
sid = new StringID(id, QByteArray(reader.getAttribute("text")));
insert(sid);
}
}
reader.readEndElement("StringHasher");
}
unsigned int StringHasher::getMemSize (void) const {
return (_hashes->SaveAll?size():count()) * 10;
}
PyObject *StringHasher::getPyObject() {
return new StringHasherPy(this);
}
std::map<long, StringIDRef> StringHasher::getIDMap() const {
std::map<long,StringIDRef> ret;
for (auto &v : _hashes->right)
ret.emplace_hint(ret.end(), v.first, StringIDRef(v.second));
return ret;
}
void StringHasher::clearMarks() const
{
for (auto &v : _hashes->right)
v.second->_flags.setFlag(StringID::Flag::Marked, false);
}
-680
View File
@@ -1,680 +0,0 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 APP_STRINGID_H
#define APP_STRINGID_H
#include <bitset>
#include <memory>
#include <QByteArray>
#include <QVector>
#include <Base/Bitmask.h>
#include <Base/Handle.h>
#include <Base/Persistence.h>
#include <CXX/Objects.hxx>
namespace Data{
class MappedName;
}
namespace App {
class StringHasher;
class StringID;
class StringIDRef;
typedef Base::Reference<StringHasher> StringHasherRef;
/** Class to store a string
*
* The main purpose of this class is to provide an efficient storage of the
* mapped geometry element name (i.e. the new Topological Naming), but it can
* also be used as a general purpose string table.
*
* The StringID is to be stored in a string table (StringHasher), and be
* referred to by an integer ID. The stored data can be optionally divided into
* two parts, prefix and postfix. This is because a new mapped name is often
* created by adding some common postfix to an existing name, so data sharing
* can be improved using the following techniques:
*
* a) reference count (through QByteArray) the main data part,
*
* b) (recursively) encode prefix and/or postfix as an integer (in the
* format of #<hex>, e.g. #1b) that references another StringID,
*
* c) Check index based name in prefix, e.g. Edge1, Vertex2, and encode
* only the text part as StringID. The index is stored separately in
* reference class StringIDRef to maximize data sharing.
*/
class AppExport StringID: public Base::BaseClass, public Base::Handled {
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
/// Flag of the stored string data
enum class Flag {
/// No flag
None = 0,
/// The stored data is binary
Binary = 1 << 0,
/// The stored data is the sha1 hash of the original content
Hashed = 1 << 1,
/** Postfix is encoded as #<hex>, e.g. #1b, where the hex integer part
* refers to another StringID.
*/
PostfixEncoded = 1 << 2,
/// The data is splited as prefix and postfix
Postfixed = 1 << 3,
/// The prefix data is split as text + index
Indexed = 1 << 4,
/** The prefix data is encoded as #<hex>, e.g. #1b, where the hex
* integer part refers to another StringID.
*/
PrefixID = 1 << 5,
/** The prefix split as text + index, where the text is encoded
* using another StringID.
*/
PrefixIDIndex = 1 << 6,
/// The string ID is persistent regardless of internal mark */
Persistent = 1 << 7,
/// Internal marked used to check if the string ID is used
Marked = 1 << 8,
};
typedef Base::Flags<Flag> Flags;
/** Constructor
* @param id: integer ID of this StringID
* @param data: input data
* @param flags: flags describes the data
*
* User code is not supposed to create StringID directly, but through StringHasher::getID()
*/
StringID(long id, const QByteArray &data, const Flags &flags=Flag::None)
:_id(id),_data(data),_flags(flags)
{}
/// Constructs an empty StringID
StringID()
:_id(0), _flags(Flag::None)
{}
virtual ~StringID();
/// Returns the ID of this StringID
long value() const {return _id;}
/// Returns all related StringIDs that used to encode this StringID
const QVector<StringIDRef> &relatedIDs() const {return _sids;}
/// @name Flag accessors
//@{
bool isBinary() const;
bool isHashed() const;
bool isPostfixed() const;
bool isPostfixEncoded() const;
bool isIndexed() const;
bool isPrefixID() const;
bool isPrefixIDIndex() const;
bool isMarked() const;
bool isPersistent() const;
//@}
/// Checks if this StringID is from the input hasher
bool isFromSameHasher(const StringHasherRef & hasher) const
{
return this->_hasher == hasher;
}
/// Returns the owner hasher
StringHasherRef getHasher() const
{
return StringHasherRef(_hasher);
}
/// Returns the data (prefix)
const QByteArray data() const {return _data;}
/// Returns the postfix
const QByteArray postfix() const {return _postfix;}
virtual PyObject *getPyObject() override;
/// Returns a Python tuple containing both the text and index
PyObject *getPyObjectWithIndex(int index);
/** Convert to string represtation of this StringID
* @param index: optional index
*
* The format is #<id>. And if index is non zero, then #<id>:<index>. Both
* <id> and <index> are in hex format.
*/
std::string toString(int index) const;
/// Light weight structure of holding a string ID and associated index
struct IndexID {
long id;
int index;
explicit operator bool() const {
return id > 0;
}
friend std::ostream & operator << (std::ostream &s, const IndexID & id) {
s << id.id;
if (id.index)
s << ':' << id.index;
return s;
}
};
/** Parse string to get ID and index
* @param name: input string
* @param eof: Whether to check the end of string. If true, then the input
* string must contain only the string representation of this
* StringID
* @param size: input string size, or -1 if the input string is zero terminated.
* @return Return the integer ID and index.
*
* The input string is expected to be in the format of #<id> or with index
* #<id>:<index>, where both id and index are in hex digits.
*/
static IndexID fromString(const char *name, bool eof=true, int size = -1);
/** Parse string to get ID and index
* @param bytes: input data
* @param eof: Whether to check the end of string. If true, then the input
* string must contain only the string representation of this
* StringID
*
* The input string is expected to be in the format of #<id> or with index
* #<id>:<index>, where both id and index are in hex digits.
*/
static IndexID fromString(const QByteArray &bytes, bool eof=true) {
return fromString(bytes.constData(), eof, bytes.size());
}
/** Get the text content of this StringID
* @param index: optional index
* @return Return the text content of this StringID. If the data is binary,
* then output in base64 encoded string.
*/
std::string dataToText(int index) const;
/** Get the content of this StringID as QByteArray
* @param bytes: output bytes
* @param index: opttional index.
*/
void toBytes(QByteArray &bytes, int index) const {
if (_postfix.size())
bytes = _data + _postfix;
else if (index)
bytes = _data + QByteArray::number(index);
else
bytes = _data;
}
/// Mark this StringID as used
void mark() const;
/// Mark the StringID as persistent regardless of usage mark
void setPersistent(bool enable);
bool operator<(const StringID &other) const {
return compare(other) < 0;
}
/** Compare StringID
* @param other: the other StringID for comparison
* @return Returns -1 if less than the other StringID, 1 if greater, or 0 if equal
*/
int compare(const StringID &other) const {
if (_hasher < other._hasher)
return -1;
if (_hasher > other._hasher)
return 1;
if (_id < other._id)
return -1;
if (_id > other._id)
return 1;
return 0;
}
friend class StringHasher;
private:
long _id;
QByteArray _data;
QByteArray _postfix;
StringHasher *_hasher = nullptr;
mutable Flags _flags;
mutable QVector<StringIDRef> _sids;
};
//////////////////////////////////////////////////////////////////////////
/** Counted reference to a StringID instance
*/
class StringIDRef
{
public:
StringIDRef()
:_sid(nullptr), _index(0)
{}
StringIDRef(StringID* p, int index=0)
: _sid(p), _index(index)
{
if (_sid)
_sid->ref();
}
StringIDRef(const StringIDRef & other)
: _sid(other._sid)
, _index(other._index)
{
if (_sid)
_sid->ref();
}
StringIDRef(StringIDRef && other)
: _sid(other._sid)
, _index(other._index)
{
other._sid = nullptr;
}
StringIDRef(const StringIDRef & other, int index)
: _sid(other._sid)
, _index(index)
{
if (_sid)
_sid->ref();
}
~StringIDRef()
{
if (_sid)
_sid->unref();
}
void reset(const StringIDRef & p = StringIDRef()) {
*this = p;
}
void reset(const StringIDRef &p, int index) {
*this = p;
this->_index = index;
}
void swap(StringIDRef &p) {
if(*this != p) {
auto tmp = p;
p = *this;
*this = tmp;
}
}
StringIDRef & operator=(StringID* p) {
if (_sid == p)
return *this;
if (_sid)
_sid->unref();
_sid = p;
if (_sid)
_sid->ref();
this->_index = 0;
return *this;
}
StringIDRef & operator=(const StringIDRef & p) {
if (_sid != p._sid) {
if (_sid)
_sid->unref();
_sid = p._sid;
if (_sid)
_sid->ref();
}
this->_index = p._index;
return *this;
}
StringIDRef & operator=(StringIDRef && p) {
if (_sid != p._sid) {
if (_sid)
_sid->unref();
_sid = p._sid;
p._sid = nullptr;
}
this->_index = p._index;
return *this;
}
bool operator<(const StringIDRef & p) const {
if (!_sid)
return true;
if (!p._sid)
return false;
int res = _sid->compare(*p._sid);
if (res < 0)
return true;
if (res > 0)
return false;
return _index < p._index;
}
bool operator==(const StringIDRef & p) const {
return _sid == p._sid && _index == p._index;
}
bool operator!=(const StringIDRef & p) const {
return _sid != p._sid || _index != p._index;
}
explicit operator bool() const {
return _sid != nullptr;
}
int getRefCount(void) const {
if (_sid)
return _sid->getRefCount();
return 0;
}
std::string toString() const {
if (_sid)
return _sid->toString(_index);
return std::string();
}
std::string dataToText() const {
if (_sid)
return _sid->dataToText(_index);
return std::string();
}
const char * constData() const {
if (_sid) {
assert(_index == 0);
assert(_sid->postfix().isEmpty());
return _sid->data().constData();
}
return "";
}
const StringID & deref() const {
return *_sid;
}
long value() const {
if (_sid)
return _sid->value();
return 0;
}
QVector<StringIDRef> relatedIDs() const {
if (_sid)
return _sid->relatedIDs();
return QVector<StringIDRef>();
}
bool isBinary() const {
if (_sid)
return _sid->isBinary();
return false;
}
bool isHashed() const {
if (_sid)
return _sid->isHashed();
return false;
}
void toBytes(QByteArray &bytes) const {
if (_sid)
_sid->toBytes(bytes, _index);
}
PyObject *getPyObject(void) {
if (_sid)
return _sid->getPyObjectWithIndex(_index);
Py_INCREF(Py_None);
return Py_None;
}
void mark() const {
if (_sid)
_sid->mark();
}
bool isMarked() const {
return _sid && _sid->isMarked();
}
bool isFromSameHasher(const StringHasherRef & hasher) const
{
return _sid && _sid->isFromSameHasher(hasher);
}
StringHasherRef getHasher() const
{
if (_sid)
return _sid->getHasher();
return StringHasherRef();
}
void setPersistent(bool enable)
{
if (_sid)
_sid->setPersistent(enable);
}
friend class StringHasher;
private:
StringID *_sid;
int _index;
};
/// A String table to map string from/to a unique integer
class AppExport StringHasher: public Base::Persistence, public Base::Handled {
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
StringHasher();
virtual ~StringHasher();
virtual unsigned int getMemSize (void) const override;
virtual void Save (Base::Writer &/*writer*/) const override;
virtual void Restore(Base::XMLReader &/*reader*/) override;
virtual void SaveDocFile (Base::Writer &/*writer*/) const override;
virtual void RestoreDocFile (Base::Reader &/*reader*/) override;
void setPersistenceFileName(const char *name) const;
const std::string &getPersistenceFileName() const;
/** Maps an arbitrary string to an integer
*
* @param text: input string.
* @param len: length of the string, or -1 if the string is 0 terminated.
* @param hashable: whether the string is hashable.
* @return Return a shared pointer to the internally stored StringID.
*
* The function maps an arbitrary text string to a unique integer ID, which
* is returned as a shared pointer to reference count the ID so that it is
* possible to prune any unused strings.
*
* If \c hashable is true and the string is longer than the threshold
* setting of this StringHasher, it will be sha1 hashed before storing, and
* the original content of the string is discarded. If else, the string is
* copied and stored inside a StringID instance.
*
* The purpose of function is to provide a short form of a stable string
* identification.
*/
StringIDRef getID(const char *text, int len=-1, bool hashable=false);
/// Option for string string data
enum class Option {
/// No option
None = 0,
/// The input data is binary
Binary = 1 << 0,
/** The input data is hashable. If the data length is longer than the
* threshold setting of the StringHasher, it will be sha1 hashed before
* storing, and the original content of the string is discarded.
*/
Hashable = 1 << 1,
/// Do not copy the data, assuming the data is constant. If this option
//is not set, the data will be copied before storing.
NoCopy = 1 << 2,
};
typedef Base::Flags<Option> Options;
/** Map text or binary data to an integer
*
* @param data: input data.
* @param options: options describing how to store the data. @sa Option.
* @return Return a shared pointer to the internally stored StringID.
*
* The function maps an arbitrary text string to a unique integer ID, which
* is returned as a shared pointer to reference count the ID so that it is
* possible to prune any unused strings.
*
* The purpose of function is to provide a short form of a stable string
* identification.
*/
StringIDRef getID(const QByteArray & data, Options options=Option::Hashable);
/** Map geometry element name to an integer */
StringIDRef getID(const Data::MappedName & name,
const QVector<StringIDRef> & sids);
/** Obtain the reference counted StringID object from numerical id
*
* @param id: string ID
* @param index: optional index of the string ID
* @return Return a shared pointer to the internally stored StringID.
*
* This function exists because the stored string may be one way hashed,
* and the original text is not persistent. The caller use this function to
* retrieve the reference count ID object after restore
*/
StringIDRef getID(long id, int index = 0) const;
/** Obtain the reference counted StringID object from numerical id and index
*
* @param id: string ID with index
* @return Return a shared pointer to the internally stored StringID.
*/
StringIDRef getID(const StringID::IndexID &id) const {
return getID(id.id, id.index);
}
std::map<long,StringIDRef> getIDMap() const;
/// Clear all string hashes
void clear();
/// Size of the hash table
size_t size() const;
/// Return the number of hashes that are used by others
size_t count() const;
virtual PyObject *getPyObject(void) override;
/** Enable/disable saving all string ID
*
* If disabled, then only save string ID that are used.
*/
void setSaveAll(bool enable);
bool getSaveAll() const;
/** Set threshold of string hashing
*
* For hashable string that are longer than the threshold, the string will
* be replaced by its sha1 hash.
*/
void setThreshold(int threshold);
int getThreshold() const;
/** Clear internal marks
*
* The internal marks on internally stored StringID instances are used to
* check if the StringID is used.
*/
void clearMarks() const;
/// Compact string storage
void compact();
class HashMap;
friend class StringID;
protected:
StringID * insert(const StringIDRef & sid);
long lastID() const;
void saveStream(std::ostream &s) const;
void restoreStream(std::istream &s, std::size_t count);
void restoreStreamNew(std::istream &s, std::size_t count);
private:
std::unique_ptr<HashMap> _hashes;
mutable std::string _filename;
};
} //namespace App
ENABLE_BITMASK_OPERATORS(App::StringID::Flag)
ENABLE_BITMASK_OPERATORS(App::StringHasher::Option)
namespace App {
inline bool StringID::isBinary() const {
return _flags.testFlag(Flag::Binary);
}
inline bool StringID::isHashed() const {
return _flags.testFlag(Flag::Hashed);
}
inline bool StringID::isPostfixed() const {
return _flags.testFlag(Flag::Postfixed);
}
inline bool StringID::isPostfixEncoded() const {
return _flags.testFlag(Flag::PostfixEncoded);
}
inline bool StringID::isIndexed() const {
return _flags.testFlag(Flag::Indexed);
}
inline bool StringID::isPrefixID() const {
return _flags.testFlag(Flag::PrefixID);
}
inline bool StringID::isPrefixIDIndex() const {
return _flags.testFlag(Flag::PrefixIDIndex);
}
inline bool StringID::isMarked() const {
return _flags.testFlag(Flag::Marked);
}
inline bool StringID::isPersistent() const {
return _flags.testFlag(Flag::Persistent);
}
inline void StringID::setPersistent(bool enable) {
_flags.setFlag(Flag::Persistent, enable);
}
} //namespace App
#endif
-70
View File
@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="StringHasherPy"
Twin="StringHasher"
TwinPointer="StringHasher"
Include="App/StringHasher.h"
FatherInclude="Base/BaseClassPy.h"
Namespace="App"
FatherNamespace="Base"
Constructor="true"
Reference="true">
<Documentation>
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
<DeveloperDocu>This is the StringHasher class</DeveloperDocu>
<UserDocu>This is the StringHasher class</UserDocu>
</Documentation>
<Methode Name="getID">
<Documentation>
<UserDocu>
getID(txt|id, base64=False) -> StringID
If the input is text, return a StringID object that is unique within this hasher. This
StringID object is reference counted. The hasher may only save hash ID's that are used.
If the input is an integer, then the hasher will try to find the StringID object stored
with the same integer value.
base64: indicate if the input 'txt' is base64 encoded binary data
</UserDocu>
</Documentation>
</Methode>
<Methode Name="isSame" Const="true">
<Documentation>
<UserDocu>Check if two hasher are the same</UserDocu>
</Documentation>
</Methode>
<Attribute Name="Count" ReadOnly="true">
<Documentation>
<UserDocu>Return count of used hashes</UserDocu>
</Documentation>
<Parameter Name="Count" Type="Int" />
</Attribute>
<Attribute Name="Size" ReadOnly="true">
<Documentation>
<UserDocu>Return the size of the hashes</UserDocu>
</Documentation>
<Parameter Name="Size" Type="Int"/>
</Attribute>
<Attribute Name="SaveAll">
<Documentation>
<UserDocu>Whether to save all string hashes regardless of its use count</UserDocu>
</Documentation>
<Parameter Name="SaveAll" Type="Boolean"/>
</Attribute>
<Attribute Name="Threshold">
<Documentation>
<UserDocu>Data length exceed this threshold will be hashed before storing</UserDocu>
</Documentation>
<Parameter Name="Threshold" Type="Int"/>
</Attribute>
<Attribute Name="Table" ReadOnly="true">
<Documentation>
<UserDocu>Return the entire string table as Int->String dictionary</UserDocu>
</Documentation>
<Parameter Name="Table" Type="Dict"/>
</Attribute>
</PythonExport>
</GenerateModel>
-150
View File
@@ -1,150 +0,0 @@
/****************************************************************************
* Copyright (c) 2018 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 "StringHasher.h"
#include "StringHasherPy.h"
#include "StringHasherPy.cpp"
using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string StringHasherPy::representation(void) const
{
std::ostringstream str;
str << "<StringHasher at " << getStringHasherPtr() << ">";
return str.str();
}
PyObject *StringHasherPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
{
return new StringHasherPy(new StringHasher);
}
// constructor method
int StringHasherPy::PyInit(PyObject* , PyObject* )
{
return 0;
}
PyObject* StringHasherPy::isSame(PyObject *args)
{
PyObject *other;
if (!PyArg_ParseTuple(args, "O!", &StringHasherPy::Type, &other)){ // convert args: Python->C
return Py::new_reference_to(Py::False());
}
auto otherHasher = static_cast<StringHasherPy*>(other)->getStringHasherPtr();
return Py::new_reference_to(Py::Boolean(getStringHasherPtr() == otherHasher));
}
PyObject* StringHasherPy::getID(PyObject *args)
{
long id = -1;
int index = 0;
PyObject *value = 0;
PyObject *base64 = Py_False;
if (!PyArg_ParseTuple(args, "l|i",&id,&index)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "O|O",&value,&base64))
return NULL; // NULL triggers exception
}
if(id>0) {
PY_TRY {
auto sid = getStringHasherPtr()->getID(id, index);
if(!sid) Py_Return;
return sid.getPyObject();
}PY_CATCH;
}
std::string txt;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(value)) {
txt = PyUnicode_AsUTF8(value);
}
#else
if (PyUnicode_Check(value)) {
PyObject* unicode = PyUnicode_AsLatin1String(value);
txt = PyString_AsString(unicode);
Py_DECREF(unicode);
}
else if (PyString_Check(value)) {
txt = PyString_AsString(value);
}
#endif
else
throw Py::TypeError("expect argument of type string");
PY_TRY {
QByteArray data;
StringIDRef sid;
if(PyObject_IsTrue(base64)) {
data = QByteArray::fromBase64(QByteArray::fromRawData(txt.c_str(),txt.size()));
sid = getStringHasherPtr()->getID(data,true);
}else
sid = getStringHasherPtr()->getID(txt.c_str(),txt.size());
return sid.getPyObject();
}PY_CATCH;
}
Py::Int StringHasherPy::getCount(void) const {
return Py::Int((long)getStringHasherPtr()->count());
}
Py::Int StringHasherPy::getSize(void) const {
return Py::Int((long)getStringHasherPtr()->size());
}
Py::Boolean StringHasherPy::getSaveAll(void) const {
return Py::Boolean(getStringHasherPtr()->getSaveAll());
}
void StringHasherPy::setSaveAll(Py::Boolean value) {
getStringHasherPtr()->setSaveAll(value);
}
Py::Int StringHasherPy::getThreshold(void) const {
return Py::Int((long)getStringHasherPtr()->getThreshold());
}
void StringHasherPy::setThreshold(Py::Int value) {
getStringHasherPtr()->setThreshold(value);
}
Py::Dict StringHasherPy::getTable() const {
Py::Dict dict;
for(auto &v : getStringHasherPtr()->getIDMap())
dict.setItem(Py::Int(v.first),Py::String(v.second.dataToText()));
return dict;
}
PyObject *StringHasherPy::getCustomAttributes(const char* /*attr*/) const
{
return 0;
}
int StringHasherPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
-64
View File
@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="StringIDPy"
Twin="StringID"
TwinPointer="StringID"
Include="App/StringHasher.h"
FatherInclude="Base/BaseClassPy.h"
Namespace="App"
FatherNamespace="Base"
Reference="true">
<Documentation>
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
<DeveloperDocu>This is the StringID class</DeveloperDocu>
<UserDocu>This is the StringID class</UserDocu>
</Documentation>
<Methode Name="isSame" Const="true">
<Documentation>
<UserDocu>Check if two StringIDs are the same</UserDocu>
</Documentation>
</Methode>
<Attribute Name="Value" ReadOnly="true">
<Documentation>
<UserDocu>Return the integer value of this ID</UserDocu>
</Documentation>
<Parameter Name="Value" Type="Int"/>
</Attribute>
<Attribute Name="Related" ReadOnly="true">
<Documentation>
<UserDocu>Return the related string IDs</UserDocu>
</Documentation>
<Parameter Name="Related" Type="List"/>
</Attribute>
<Attribute Name="Data" ReadOnly="true">
<Documentation>
<UserDocu>Return the data associated with this ID</UserDocu>
</Documentation>
<Parameter Name="Data" Type="String"/>
</Attribute>
<Attribute Name="IsBinary" ReadOnly="true">
<Documentation>
<UserDocu>Check if the data is binary, </UserDocu>
</Documentation>
<Parameter Name="IsBinary" Type="Boolean"/>
</Attribute>
<Attribute Name="IsHashed" ReadOnly="true">
<Documentation>
<UserDocu>Check if the data is hash, if so 'Data' returns a base64 encoded string of the raw hash</UserDocu>
</Documentation>
<Parameter Name="IsHashed" Type="Boolean"/>
</Attribute>
<Attribute Name="Index" ReadOnly="false">
<Documentation>
<UserDocu>Geometry index. Only meaningful for geometry element name</UserDocu>
</Documentation>
<Parameter Name="Index" Type="Int"/>
</Attribute>
<ClassDeclarations>private:
friend class StringID;
int _index = 0;
</ClassDeclarations>
</PythonExport>
</GenerateModel>
-91
View File
@@ -1,91 +0,0 @@
/****************************************************************************
* Copyright (c) 2018 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 "StringHasher.h"
#include "StringIDPy.h"
#include "StringIDPy.cpp"
using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string StringIDPy::representation(void) const
{
return getStringIDPtr()->toString(_index);
}
PyObject* StringIDPy::isSame(PyObject *args)
{
PyObject *other;
if (!PyArg_ParseTuple(args, "O!", &StringIDPy::Type, &other)) { // convert args: Python->C
return Py::new_reference_to(Py::False());
}
auto otherPy = static_cast<StringIDPy*>(other);
return Py::new_reference_to(Py::Boolean(
otherPy->getStringIDPtr() == this->getStringIDPtr()
&& otherPy->_index == this->_index));
}
Py::Int StringIDPy::getValue(void) const {
return Py::Int(getStringIDPtr()->value());
}
Py::List StringIDPy::getRelated(void) const {
Py::List list;
for (auto &id : getStringIDPtr()->relatedIDs())
list.append(Py::Long(id.value()));
return list;
}
Py::String StringIDPy::getData(void) const {
return Py::String(getStringIDPtr()->dataToText(this->_index));
}
Py::Boolean StringIDPy::getIsBinary(void) const {
return Py::Boolean(getStringIDPtr()->isBinary());
}
Py::Boolean StringIDPy::getIsHashed(void) const {
return Py::Boolean(getStringIDPtr()->isHashed());
}
Py::Int StringIDPy::getIndex(void) const {
return Py::Int(this->_index);
}
void StringIDPy::setIndex(Py::Int index) {
this->_index = index;
}
PyObject *StringIDPy::getCustomAttributes(const char* /*attr*/) const
{
return 0;
}
int StringIDPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
+25 -52
View File
@@ -22,17 +22,11 @@
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com)
* Added support of in-line transformation using boost iostream for memory
efficiency
*/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <iostream>
# include <string>
#endif
@@ -45,31 +39,12 @@ static const std::string base64_chars =
"0123456789+/";
const signed char *Base::base64_decode_table() {
static const signed char _table[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -1, -2, -1, -1, // 0-15
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, // 48-63
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
};
return _table;
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::size_t Base::base64_encode(char *out, void const* in, std::size_t in_len) {
char *ret = out;
unsigned char const *bytes_to_encode = reinterpret_cast<unsigned char const*>(in);
std::string Base::base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
@@ -84,7 +59,7 @@ std::size_t Base::base64_encode(char *out, void const* in, std::size_t in_len) {
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
*ret++ = base64_chars[char_array_4[i]];
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
@@ -100,41 +75,37 @@ std::size_t Base::base64_encode(char *out, void const* in, std::size_t in_len) {
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
*ret++ = base64_chars[char_array_4[j]];
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
*ret++ = '=';
ret += '=';
}
return ret-out;
return ret;
}
std::pair<std::size_t, std::size_t> Base::base64_decode(
void *_out, char const *in, std::size_t in_len)
{
unsigned char *out = reinterpret_cast<unsigned char*>(_out);
unsigned char *ret = out;
char const *input = in;
std::string Base::base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
static const signed char *table = base64_decode_table();
while (in_len-- && *in != '=') {
const signed char v = table[(int)(*in++)];
if(v < 0)
break;
char_array_4[i++] = (unsigned char)v;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
*ret++ = char_array_3[i];
ret += char_array_3[i];
i = 0;
}
}
@@ -143,13 +114,15 @@ std::pair<std::size_t, std::size_t> Base::base64_decode(
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) *ret++ = char_array_3[j];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return std::make_pair((std::size_t)(ret-out), (std::size_t)(in-input));
return ret;
}
+5 -366
View File
@@ -23,381 +23,20 @@
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com)
* Added support of in-line transformation using boost iostream for memory
efficiency
*/
#ifndef BASE_BASE64_H
#define BASE_BASE64_H
#include <FCGlobal.h>
#include <string>
#include <memory>
#include <vector>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
namespace Base
{
/// Returns the max bytes of a encoded base64 string
inline std::size_t base64_encode_size(std::size_t len) {
return 4 * ((len + 2) / 3);
}
std::string BaseExport base64_encode(unsigned char const* , unsigned int len);
std::string BaseExport base64_decode(std::string const& s);
/// Returns the max bytes of a decoded base64 binary string
inline std::size_t base64_decode_size(std::size_t len) {
return len / 4 * 3;
}
/** Encode input binary with base64
* @param out: output buffer with minimum size of base64_encode(len)
* appending new data.
* @param in: input binary data
* @param len: input length
* @return The character count written to output.
*/
BaseExport std::size_t base64_encode(char *out, void const *in , std::size_t len);
/** Return the internal base64 decoding table
*
* The table maps from any 8-bit character to the decoded binary bits.
* Valid base64 characters are mapped to the corresponding 6-bit binary
* data. White space (space, tab, vtab, CR and LF) characters are mapped
* to -2. Other invalid characters are mapped to -1.
*/
BaseExport const signed char *base64_decode_table();
/** Decode the input base64 string into binary data
* @param out: output buffer with minimum size of base64_encode(len)
* appending new data.
* @param in: input binary data
* @param len: input length
* @return Return a pair of output size and input read size. Compare the
* read size to input size to check for error.
*/
BaseExport std::pair<std::size_t, std::size_t> base64_decode(
void *out, char const *, std::size_t len);
/** Encode input binary into base64 string
* @param out: output string. Note that the string is not cleared before
* adding new content.
* @param in: input binary data
* @param len: input length
*/
inline void base64_encode(std::string &out, void const* in , std::size_t len) {
std::size_t size = out.size();
out.resize(size + base64_encode_size(len));
len = base64_encode(&out[size],in,len);
out.resize(size+len);
}
/** Encode input binary into base64 string
* @param in: input binary data
* @param len: input length
* @return Return the base64 string.
*/
inline std::string base64_encode(void const* in , std::size_t len) {
std::string out;
base64_encode(out,in,len);
return out;
}
/** Decode base64 string into binary data
* @param out: output binary data. Note that the data is not cleared before
* adding new content.
* @param in: input base64 string
* @param len: input length
* @return Return the processed input length. Compare this with the
* argument \c len to check for error.
*/
template<typename T>
inline std::size_t base64_decode(T &out, char const *in, std::size_t len) {
std::size_t size = out.size();
out.resize(size + base64_decode_size(len));
std::pair<std::size_t,std::size_t> res = base64_decode(&out[size],in,len);
out.resize(size + res.first);
return res.second;
}
/** Decode base64 string into binary data
* @param out: output binary data. Note that the data is not cleared before
* adding new content.
* @param s: input base64 string
* @return Return the processed input length. Compare this with the
* argument \c len to check for error.
*/
template<typename T>
inline std::size_t base64_decode(T &out, std::string const &s) {
return base64_decode(out,s.c_str(),s.size());
}
/** Decode base64 string into binary data
* @param out adding new content.
* @param s: input base64 string
* @return Return the decoded binary data.
*/
inline std::string base64_decode(std::string const& s) {
std::string out;
base64_decode(out,s.c_str(),s.size());
return out;
}
namespace bio = boost::iostreams;
/** A base64 encoder that can be used as a boost iostream filter
*
* @sa See create_base64_encoder() for example usage
*/
struct base64_encoder {
typedef char char_type;
struct category : bio::multichar_output_filter_tag
, bio::closable_tag
, bio::optimally_buffered_tag
{};
/** Constructor
* @param line_size: line size for the output base64 string, 0 to
* disable segmentation.
*/
base64_encoder(std::size_t line_size)
:line_size(line_size)
{
}
std::streamsize optimal_buffer_size() const {
return base64_decode_size(line_size);
}
template<typename Device>
void close(Device &dev)
{
if(pending_size)
base64_encode(buffer,pending,pending_size);
if(buffer.size()) {
bio::write(dev,buffer.c_str(),buffer.size());
if(line_size)
bio::put(dev,'\n');
buffer.clear();
}else if(pos && line_size)
bio::put(dev,'\n');
}
template<typename Device>
std::streamsize write(Device& dev, const char_type* s, std::streamsize n) {
std::streamsize res = n;
if(pending_size) {
while(n && pending_size < 3) {
pending[pending_size++] = *s++;
--n;
}
if(pending_size!=3)
return res;
base64_encode(buffer,pending,3);
}
pending_size = n%3;
n = n/3*3;
base64_encode(buffer,s,n);
s += n;
for(unsigned i=0;i<pending_size;++i)
pending[i] = s[i];
const char *buf = buffer.c_str();
const char *end = buf + buffer.size();
if(line_size && buffer.size()>=line_size-pos) {
bio::write(dev,buf,line_size-pos);
bio::put(dev,'\n');
buf += line_size-pos;
pos = 0;
for(; end-buf>=(int)line_size; buf+=line_size) {
bio::write(dev,buf,line_size);
bio::put(dev,'\n');
}
}
pos += end-buf;
bio::write(dev,buf,end-buf);
buffer.clear();
return n;
}
std::size_t line_size;
std::size_t pos = 0;
std::size_t pending_size = 0;
unsigned char pending[3];
std::string buffer;
};
/** A base64 decoder that can be used as a boost iostream filter
*
* @sa See create_base64_decoder() for example usage
*/
struct base64_decoder {
typedef char char_type;
struct category : bio::multichar_input_filter_tag
, bio::optimally_buffered_tag
{};
/** Constructor
* @param line_size: line size of the encoded base64 string. This is
* used just as a suggestion for better buffering.
* @param silent: whether to throw on invalid non white space character.
*/
base64_decoder(std::size_t line_size, bool silent)
:line_size(line_size), silent(silent)
{
}
std::streamsize optimal_buffer_size() const {
return base64_encode_size(line_size?line_size:1024);
}
template<typename Device>
std::streamsize read(Device& dev, char_type* s, std::streamsize n) {
static const signed char *table = base64_decode_table();
if(!n)
return 0;
std::streamsize count = 0;
for(;;) {
while(pending_out<out_count) {
*s++ = char_array_3[pending_out++];
++count;
if(--n == 0)
return count;
}
if(eof)
return count?count:-1;
for(;;) {
int d = bio::get(dev);
if(d < 0) {
eof = true;
if(pending_in<=1) {
if(pending_in == 1 && !silent)
throw BOOST_IOSTREAMS_FAILURE("Unexpected ending of base64 string");
return count?count:-1;
}
out_count = pending_in-1;
pending_in = 4;
} else {
signed char c = table[d];
if(c < 0) {
if(c==-2 || silent)
continue;
throw BOOST_IOSTREAMS_FAILURE("Invalid character in base64 string");
}
char_array_4[pending_in++] = (char)c;
}
if(pending_in == 4) {
pending_out = pending_in = 0;
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
break;
}
}
}
}
std::size_t line_size;
std::uint8_t pending_in = 0;
char char_array_4[4];
std::uint8_t pending_out = 3;
std::uint8_t out_count = 3;
char char_array_3[3];
bool silent;
bool eof = false;
};
/** Create an output stream that transforms the input binary data to base64 strings
*
* @param out: the downstream output stream that will be fed with base64 string
* @param line_size: line size of the base64 string. Zero to disable segmenting.
*
* @return A unique pointer to an output stream that can transforms the
* input binary data to base64 strings.
*/
inline std::unique_ptr<std::ostream> create_base64_encoder(
std::ostream &out, std::size_t line_size=80)
{
std::unique_ptr<std::ostream> res(new bio::filtering_ostream);
bio::filtering_ostream *f = static_cast<bio::filtering_ostream*>(res.get());
f->push(base64_encoder(line_size));
f->push(out);
return res;
}
/** Create an output stream that stores the input binary data to file as base64 strings
*
* @param filename: the output file path
* @param line_size: line size of the base64 string. Zero to disable segmenting.
*
* @return A unique pointer to an output stream that can transforms the
* input binary data to base64 strings.
*/
inline std::unique_ptr<std::ostream> create_base64_encoder(
const std::string &filepath, std::size_t line_size=80)
{
std::unique_ptr<std::ostream> res(new bio::filtering_ostream);
bio::filtering_ostream *f = static_cast<bio::filtering_ostream*>(res.get());
f->push(base64_encoder(line_size));
f->push(bio::file_sink(filepath));
return res;
}
/** Create an input stream that can transform base64 into binary
*
* @param in: input upstream.
* @param line_size: line size of the encoded base64 string. This is
* used just as a suggestion for better buffering.
* @param silent: whether to throw on invalid non white space character.
*
* @return A unique pointer to an input stream that read from the given
* upstream and transform the read base64 strings into binary data.
*/
inline std::unique_ptr<std::istream> create_base64_decoder(
std::istream &in, std::size_t line_size=80, bool silent=true)
{
std::unique_ptr<std::istream> res(new bio::filtering_istream);
bio::filtering_istream *f = static_cast<bio::filtering_istream*>(res.get());
f->push(base64_decoder(line_size,silent));
f->push(in);
return res;
}
/** Create an input stream that can transform base64 into binary
*
* @param filepath: input file.
* @param ending: optional ending character. If non zero, the filter
* will signal EOF when encounter this character.
* @param putback: if true and the filter read the ending character
* it will put it back into upstream
* @param line_size: line size of the encoded base64 string. This is
* used just as a suggestion for better buffering.
* @param silent: whether to throw on invalid non white space character.
*
* @return A unique pointer to an input stream that read from the given
* file and transform the read base64 strings into binary data.
*/
inline std::unique_ptr<std::istream> create_base64_decoder(
const std::string &filepath, std::size_t line_size=80, bool silent=true)
{
std::unique_ptr<std::istream> res(new bio::filtering_istream);
bio::filtering_istream *f = static_cast<bio::filtering_istream*>(res.get());
f->push(base64_decoder(line_size,silent));
f->push(bio::file_source(filepath));
return res;
}
} // namespace Base
}
#endif
-7
View File
@@ -109,7 +109,6 @@ template <typename Enum>
class Flags {
static_assert(std::is_enum<Enum>::value, "Flags is only usable on enumeration types.");
Enum i;
typedef typename std::underlying_type<Enum>::type underlying_type;
public:
constexpr inline Flags(Enum f) : i(f) {}
@@ -124,12 +123,6 @@ public:
using u = typename std::underlying_type<Enum>::type;
return static_cast<u>(i) == static_cast<u>(f.i);
}
Enum getValue() const {
return i;
}
underlying_type toUnderlyingType() const {
return static_cast<underlying_type>(i);
}
};
}
+2 -2
View File
@@ -610,7 +610,7 @@ inline bool BoundBox3<_Precision>::IntersectionPoint (const Vector3<_Precision>
rc = IntersectPlaneWithLine(i, rcVct, rcVctDir, cVctRes);
if (!cCmpBound.IsInBox(cVctRes))
rc = false;
if (rc) {
if (rc == true) {
// does intersection point lie in desired direction
// or was found the opposing side?
// -> scalar product of both direction vectors > 0 (angle < 90)
@@ -773,7 +773,7 @@ inline typename BoundBox3<_Precision>::SIDE BoundBox3<_Precision>::GetSideFromRa
Vector3<_Precision>& rcInt) const
{
Vector3<_Precision> cP0, cP1;
if (!IntersectWithLine(rclPt, rclDir, cP0, cP1))
if (IntersectWithLine(rclPt, rclDir, cP0, cP1) == false)
return INVALID;
Vector3<_Precision> cOut;
+4 -4
View File
@@ -116,7 +116,7 @@ void Builder3D::endPoints()
void Builder3D::addSinglePoint(float x, float y, float z,short pointSize, float color_r,float color_g,float color_b)
{
// addSinglePoint() not between startXXX() and endXXX() allowed
assert(!bStartEndOpen);
assert( bStartEndOpen == false );
result << "Separator { ";
result << "Material { ";
@@ -155,7 +155,7 @@ void Builder3D::addSinglePoint(const Base::Vector3f &vec, short pointSize, float
void Builder3D::addText(float pos_x, float pos_y , float pos_z,const char * text, float color_r,float color_g,float color_b)
{
// addSinglePoint() not between startXXX() and endXXX() allowed
assert(!bStartEndOpen);
assert( bStartEndOpen == false );
result << "Separator { "
<< "Material { diffuseColor " << color_r << " "<< color_g << " "<< color_b << "} "
@@ -172,8 +172,8 @@ void Builder3D::addText(const Base::Vector3f &vec,const char * text, float color
void Builder3D::clear ()
{
// under gcc stringstream::str() returns a copy not a reference
#if defined(_MSC_VER)
// Under VC6 string::clear() doesn't exist, under gcc stringstream::str() returns a copy not a reference
#if defined(_MSC_VER) && _MSC_VER >= 1400
result.str().clear();
#endif
result.clear();
-2
View File
@@ -34,7 +34,6 @@
#include <frameobject.h>
#include "ConsoleObserver.h"
#include "Interpreter.h"
using namespace Base;
@@ -264,7 +263,6 @@ std::stringstream &LogLevel::prefix(std::stringstream &str, const char *src, int
}
if (print_tag) str << '<' << tag << "> ";
if (print_src==2) {
PyGILStateLocker lock;
PyFrameObject* frame = PyEval_GetFrame();
if (frame) {
line = PyFrame_GetLineNumber(frame);
+2 -2
View File
@@ -556,7 +556,7 @@ bool FileInfo::createDirectories() const
bool FileInfo::deleteDirectory() const
{
if (!isDir())
if (isDir() == false )
return false;
#if defined (FC_OS_WIN32)
std::wstring wstr = toStdWString();
@@ -570,7 +570,7 @@ bool FileInfo::deleteDirectory() const
bool FileInfo::deleteDirectoryRecursive() const
{
if (!isDir())
if (isDir() == false )
return false;
std::vector<Base::FileInfo> List = getDirectoryContent();
+42
View File
@@ -25,10 +25,52 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cassert>
# include <iostream>
#endif
#include <QAtomicInt>
#include "Handle.h"
using namespace Base;
//**************************************************************************
// Construction/Destruction
Handled::Handled()
: _lRefCount(new QAtomicInt(0))
{
}
Handled::~Handled()
{
if (static_cast<int>(*_lRefCount) != 0)
std::cerr << "Reference counter of deleted object is not zero!!!!!" << std::endl;
delete _lRefCount;
}
void Handled::ref() const
{
_lRefCount->ref();
}
void Handled::unref() const
{
assert(*_lRefCount > 0);
if (!_lRefCount->deref()) {
delete this;
}
}
int Handled::getRefCount() const
{
return static_cast<int>(*_lRefCount);
}
const Handled& Handled::operator = (const Handled&)
{
// we must not assign _lRefCount
return *this;
}
+22 -51
View File
@@ -29,9 +29,8 @@
#include <FCGlobal.h>
#endif
#include <assert.h>
#include <atomic>
#include <iostream>
class QAtomicInt;
namespace Base
{
@@ -73,18 +72,6 @@ public:
_toHandle->unref();
}
void reset(const Reference<T> &p=Reference<T>()) {
*this = p;
}
void swap(Reference<T> &p) {
if(*this != p) {
auto tmp = p;
p = *this;
*this = tmp;
}
}
//**************************************************************************
// operator implementation
@@ -129,18 +116,18 @@ public:
}
/** Lower operator, needed for sorting in maps and sets */
// bool operator<(const Reference<T>& p) const {
// return _toHandle < p._toHandle;
// }
bool operator<(const Reference<T>& p) const {
return _toHandle < p._toHandle;
}
/** Equal operator */
// bool operator==(const Reference<T>& p) const {
// return _toHandle == p._toHandle;
// }
//
// bool operator!=(const Reference<T>& p) const {
// return _toHandle != p._toHandle;
// }
bool operator==(const Reference<T>& p) const {
return _toHandle == p._toHandle;
}
bool operator!=(const Reference<T>& p) const {
return _toHandle != p._toHandle;
}
//**************************************************************************
@@ -173,36 +160,20 @@ private:
class BaseExport Handled
{
public:
Handled()
:_lRefCount(0)
{}
Handled();
virtual ~Handled();
Handled(const Handled&) = delete;
void ref() const;
void unref() const;
virtual ~Handled()
{
if (_lRefCount != 0)
std::cerr << "Reference counter of deleted object is not zero!!!!!" << std::endl;
}
void ref() const {++_lRefCount;}
int unref() const
{
int res = --_lRefCount;
if (res == 0)
delete this;
else
assert(res>0);
return res;
}
int getRefCount(void) const {return _lRefCount;}
const Handled& operator = (const Handled&) {return *this;}
int getRefCount() const;
const Handled& operator = (const Handled&);
private:
mutable std::atomic<int> _lRefCount;
Handled(const Handled&);
private:
QAtomicInt* _lRefCount;
};
} // namespace Base
+11 -27
View File
@@ -513,7 +513,8 @@ void InterpreterSingleton::addType(PyTypeObject* Type,PyObject* Module, const ch
// This function is responsible for adding inherited slots from a type's base class.
if (PyType_Ready(Type) < 0)
return;
PyModule_AddObject(Module, Name, Base::getTypeAsObject(Type));
union PyType_Object pyType = {Type};
PyModule_AddObject(Module, Name, pyType.o);
}
void InterpreterSingleton::addPythonPath(const char* Path)
@@ -824,12 +825,7 @@ int getSWIGVersionFromModule(const std::string& module)
}
#if (defined(HAVE_SWIG) && (HAVE_SWIG == 1))
namespace Swig_python {
extern int createSWIGPointerObj_T(const char* TypeName, void* obj, PyObject** ptr, int own);
extern int convertSWIGPointerObj_T(const char* TypeName, PyObject* obj, void** ptr, int flags);
extern void cleanupSWIG_T(const char* TypeName);
extern int getSWIGPointerTypeObj_T(const char* TypeName, PyTypeObject** ptr);
}
namespace Swig_python { extern int createSWIGPointerObj_T(const char* TypeName, void* obj, PyObject** ptr, int own); }
#endif
PyObject* InterpreterSingleton::createSWIGPointerObj(const char* Module, const char* TypeName, void* Pointer, int own)
@@ -854,6 +850,10 @@ PyObject* InterpreterSingleton::createSWIGPointerObj(const char* Module, const c
throw Base::RuntimeError("No SWIG wrapped library loaded");
}
#if (defined(HAVE_SWIG) && (HAVE_SWIG == 1))
namespace Swig_python { extern int convertSWIGPointerObj_T(const char* TypeName, PyObject* obj, void** ptr, int flags); }
#endif
bool InterpreterSingleton::convertSWIGPointerObj(const char* Module, const char* TypeName, PyObject* obj, void** ptr, int flags)
{
int result = 0;
@@ -876,6 +876,10 @@ bool InterpreterSingleton::convertSWIGPointerObj(const char* Module, const char*
throw Base::RuntimeError("No SWIG wrapped library loaded");
}
#if (defined(HAVE_SWIG) && (HAVE_SWIG == 1))
namespace Swig_python { extern void cleanupSWIG_T(const char* TypeName); }
#endif
void InterpreterSingleton::cleanupSWIG(const char* TypeName)
{
PyGILStateLocker locker;
@@ -885,23 +889,3 @@ void InterpreterSingleton::cleanupSWIG(const char* TypeName)
(void)TypeName;
#endif
}
PyTypeObject* InterpreterSingleton::getSWIGPointerTypeObj(const char* Module, const char* TypeName)
{
int result = 0;
PyTypeObject* proxy = nullptr;
PyGILStateLocker locker;
(void)Module;
#if (defined(HAVE_SWIG) && (HAVE_SWIG == 1))
result = Swig_python::getSWIGPointerTypeObj_T(TypeName, &proxy);
#else
(void)TypeName;
result = -1; // indicates error
#endif
if (result == 0)
return proxy;
// none of the SWIG's succeeded
throw Base::RuntimeError("No SWIG wrapped library loaded");
}
-1
View File
@@ -283,7 +283,6 @@ public:
PyObject* createSWIGPointerObj(const char* Modole, const char* TypeName, void* Pointer, int own);
bool convertSWIGPointerObj(const char* Module, const char* TypeName, PyObject* obj, void** ptr, int flags);
void cleanupSWIG(const char* TypeName);
PyTypeObject* getSWIGPointerTypeObj(const char* Module, const char* TypeName);
//@}
/** @name methods for debugging facility
+13 -14
View File
@@ -18,12 +18,12 @@
<DeveloperDocu>This is the Matrix export class</DeveloperDocu>
<UserDocu>Base.Matrix class.\n
A 4x4 Matrix.
In particular, this matrix can represent an affine transformation, that is,
given a 3D vector `x`, apply the transformation y = M*x + b, where the matrix
`M` is a linear map and the vector `b` is a translation.
`y` can be obtained using a linear transformation represented by the 4x4 matrix
`A` conformed by the augmented 3x4 matrix (M|b), augmented by row with
(0,0,0,1), therefore: (y, 1) = A*(x, 1).\n
In particular, this matrix can represent an affine transformation, that is, given a
3D vector `x`, apply the transformation y = M*x + b, where the matrix `M` is a linear
map and the vector `b` is a translation.
`y` can be obtained using a linear transformation represented by the 4x4 matrix `A`
conformed by the augmented 3x4 matrix (M|b), augmented by row with (0,0,0,1), therefore:
(y, 1) = A*(x, 1).\n
The following constructors are supported:\n
Matrix()
Empty constructor.\n
@@ -34,9 +34,8 @@ Matrix(*coef)
Define from 16 coefficients of the 4x4 matrix.
coef : sequence of float\n The sequence can have up to 16 elements which complete the matrix by rows.\n
Matrix(vector1, vector2, vector3, vector4)
Define from four 3D vectors which represent the columns of the 3x4 submatrix,
useful to represent an affine transformation. The fourth row is made up by
(0,0,0,1).
Define from four 3D vectors which represent the columns of the 3x4 submatrix, useful
to represent an affine transformation. The fourth row is made up by (0,0,0,1).
vector1 : Base.Vector
vector2 : Base.Vector
vector3 : Base.Vector
@@ -116,7 +115,7 @@ matrix2 : Base.Matrix</UserDocu>
<Documentation>
<UserDocu>col(index) -> Base.Vector\n
Return the vector of a column, that is, the vector generated by the three
first elements of the specified column.\n
first elements of the specified column.
index : int\n Required column index.</UserDocu>
</Documentation>
</Methode>
@@ -162,21 +161,21 @@ vector : Base.Vector</UserDocu>
<Methode Name="rotateX">
<Documentation>
<UserDocu>rotateX(angle) -> None\n
Rotate around X axis.\n
Rotate around X axis.
angle : float\n Angle in radians.</UserDocu>
</Documentation>
</Methode>
<Methode Name="rotateY">
<Documentation>
<UserDocu>rotateY(angle) -> None\n
Rotate around Y axis.\n
Rotate around Y axis.
angle : float\n Angle in radians.</UserDocu>
</Documentation>
</Methode>
<Methode Name="rotateZ">
<Documentation>
<UserDocu>rotateZ(angle) -> None\n
Rotate around Z axis.\n
Rotate around Z axis.
angle : float\n Angle in radians.</UserDocu>
</Documentation>
</Methode>
@@ -193,7 +192,7 @@ vector : Base.Vector</UserDocu>
<Methode Name="multVec" Const="true">
<Documentation>
<UserDocu>multVec(vector) -> Base.Vector\n
Compute the transformed vector using the matrix.\n
Compute the transformed vector using the matrix.
vector : Base.Vector</UserDocu>
</Documentation>
</Methode>
+8 -2
View File
@@ -122,13 +122,19 @@ MemDebug::MemDebug()
// Open a log file for the hook functions to use
if ( logFile != NULL )
throw std::runtime_error("Base::MemDebug::MemDebug():38: Don't call the constructor by your self!");
#if (_MSC_VER >= 1400)
fopen_s( &logFile, "MemLog.txt", "w" );
if ( logFile == NULL )
throw std::runtime_error("Base::MemDebug::MemDebug():41: File IO Error. Can't open log file...");
_strtime_s( timeStr, 15 );
_strdate_s( dateStr, 15 );
#elif (_MSC_VER >= 1200)
logFile = fopen( "MemLog.txt", "w" );
if ( logFile == NULL )
throw std::runtime_error("Base::MemDebug::MemDebug():41: File IO Error. Can't open log file...");
_strtime( timeStr );
_strdate( dateStr );
#endif
fprintf( logFile,
"Memory Allocation Log File for FreeCAD, run at %s on %s.\n",
timeStr, dateStr );
-2
View File
@@ -201,8 +201,6 @@ public:
//@{
/// set a string value
void SetASCII(const char* Name, const char *sValue);
/// set a string value
void SetASCII(const char* Name, const std::string &sValue) { SetASCII(Name, sValue.c_str()); }
/// read a string values
std::string GetASCII(const char* Name, const char * pPreset=nullptr) const;
/// remove a string value from this group
+2 -3
View File
@@ -124,14 +124,13 @@ void Persistence::dumpToStream(std::ostream& stream, int compression)
void Persistence::restoreFromStream(std::istream& stream)
{
zipios::ZipInputStream zipstream(stream);
Base::ZipReader zreader(zipstream,std::string("<stream>"));
Base::XMLReader reader(zreader);
Base::XMLReader reader("", zipstream);
if (!reader.isValid())
throw Base::ValueError("Unable to construct reader");
reader.readElement("Content");
Restore(reader);
reader.readFiles();
reader.readFiles(zipstream);
restoreFinished();
}
-4
View File
@@ -141,10 +141,6 @@ public:
* @see Base::Reader,Base::XMLReader
*/
virtual void RestoreDocFile(Reader &/*reader*/);
/// Called by reader to set restoring error
virtual void SetRestoreError(const char *) {}
/// Encodes an attribute upon saving.
static std::string encodeAttribute(const std::string&);
+1 -1
View File
@@ -37,7 +37,7 @@ base : Base.Vector
rotation : Base.Rotation
center : Base.Vector\n
Placement(base, axis, angle)
define position and rotation.
define position and rotation
base : Base.Vector
axis : Base.Vector
angle : float</UserDocu>
+2 -2
View File
@@ -234,7 +234,7 @@ PyObject* PlacementPy::pow(PyObject* args)
PyObject* shorten = Py_True;
if (!PyArg_ParseTuple(args, "d|O!", &t, &(PyBool_Type), &shorten))
return nullptr;
Base::Placement ret = getPlacementPtr()->pow(t, PyObject_IsTrue(shorten) ? true : false);
Base::Placement ret = getPlacementPtr()->pow(t, PyObject_IsTrue(shorten));
return new PlacementPy(new Placement(ret));
}
@@ -247,7 +247,7 @@ PyObject* PlacementPy::sclerp(PyObject* args)
if (!PyArg_ParseTuple(args, "O!d|O!", &(PlacementPy::Type), &pyplm2, &t, &(PyBool_Type), &shorten))
return nullptr;
Base::Placement plm2 = static_cast<Base::PlacementPy*>(pyplm2)->value();
Base::Placement ret = Base::Placement::sclerp(*getPlacementPtr(), plm2, t, PyObject_IsTrue(shorten) ? true : false);
Base::Placement ret = Base::Placement::sclerp(*getPlacementPtr(), plm2, t, PyObject_IsTrue(shorten));
return new PlacementPy(new Placement(ret));
}
+4 -4
View File
@@ -103,7 +103,7 @@ static void
PyBaseProxy_dealloc(PyObject* self)
{
/* Clear weakrefs first before calling any destructors */
if (reinterpret_cast<PyBaseProxy*>(self)->weakreflist != nullptr)
if (reinterpret_cast<PyBaseProxy*>(self)->weakreflist)
PyObject_ClearWeakRefs(self);
Py_TYPE(self)->tp_free(self);
}
@@ -349,7 +349,7 @@ int PyObjectBase::__setattro(PyObject *obj, PyObject *attro, PyObject *value)
//Hint: In general we don't allow to delete attributes (i.e. value=0). However, if we want to allow
//we must check then in _setattr() of all subclasses whether value is 0.
if ( value==nullptr ) {
if (!value) {
PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr);
return -1;
}
@@ -409,7 +409,7 @@ PyObject *PyObjectBase::_getattr(const char *attr)
// As fallback solution use Python's default method to get generic attributes
PyObject *w, *res;
w = PyUnicode_InternFromString(attr);
if (w != nullptr) {
if (w) {
res = PyObject_GenericGetAttr(this, w);
Py_XDECREF(w);
return res;
@@ -429,7 +429,7 @@ int PyObjectBase::_setattr(const char *attr, PyObject *value)
PyObject *w;
// As fallback solution use Python's default method to get generic attributes
w = PyUnicode_InternFromString(attr); // new reference
if (w != nullptr) {
if (w) {
// call methods from tp_getset if defined
int res = PyObject_GenericSetAttr(this, w, value);
Py_DECREF(w);
+11 -6
View File
@@ -91,6 +91,15 @@
#define PyMOD_INIT_FUNC(name) PyMODINIT_FUNC PyInit_##name(void)
#define PyMOD_Return(name) return name
/**
* Union to convert from PyTypeObject to PyObject pointer.
*/
union PyType_Object {
PyTypeObject *t;
PyObject *o;
};
/*------------------------------
* Basic defines
@@ -114,12 +123,8 @@ inline void Assert(int expr, char *msg) // C++ assert
};
}
inline PyObject* getTypeAsObject(PyTypeObject* type) {
// See https://en.cppreference.com/w/cpp/string/byte/memcpy
// and https://en.cppreference.com/w/cpp/language/reinterpret_cast
PyObject* obj;
std::memcpy(&obj, &type, sizeof type);
return obj;
inline bool asBoolean(PyObject *obj) {
return PyObject_IsTrue(obj) != 0;
}
}
+2 -1
View File
@@ -595,7 +595,8 @@ Py::Object QuantityPy::getUnit() const
void QuantityPy::setUnit(Py::Object arg)
{
Py::Type UnitType(Base::getTypeAsObject(&Base::UnitPy::Type));
union PyType_Object pyType = {&(Base::UnitPy::Type)};
Py::Type UnitType(pyType.o);
if(!arg.isType(UnitType))
throw Py::AttributeError("Not yet implemented");
+145 -380
View File
@@ -29,10 +29,6 @@
#include <locale>
#include <boost/ref.hpp>
#include <boost/algorithm/string/predicate.hpp>
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include "Reader.h"
#include "Base64.h"
#include "Console.h"
@@ -48,73 +44,24 @@
#include <zipios++/zipinputstream.h>
FC_LOG_LEVEL_INIT("Base",true,true);
XERCES_CPP_NAMESPACE_USE
using namespace std;
using namespace Base;
namespace bio = boost::iostreams;
static std::string _ReaderContext;
#define _FC_READER_THROW(_excp,_msg) \
FC_THROWM(_excp, _msg << "\nIn context: " << _ReaderContext);
#define FC_READER_THROW(_msg) _FC_READER_THROW(Base::XMLParseException, _msg)
ReaderContext::ReaderContext(const char *name)
{
init(name);
}
ReaderContext::ReaderContext(const std::string &name)
{
init(name.c_str());
}
void ReaderContext::init(const char *name)
{
size = std::string::npos;
if(name && name[0]) {
size = _ReaderContext.size();
_ReaderContext += "|";
_ReaderContext += name;
}
}
ReaderContext::~ReaderContext()
{
if(size != std::string::npos)
_ReaderContext.resize(size);
}
// ---------------------------------------------------------------------------
// Base::XMLReader: Constructors and Destructor
// ---------------------------------------------------------------------------
Base::XMLReader::XMLReader(Base::Reader &reader, std::size_t bufsize)
: DocumentSchema(0), ProgramVersion(""), FileVersion(reader.getFileVersion()), Level(0),
CharacterOffset(-1), ReadType(None), _File(reader.getFileName()), _valid(false),
_verbose(true), _reader(&reader), _ownReader(false)
{
init(bufsize);
}
Base::XMLReader::XMLReader(const char *name, std::istream &str, std::size_t bufsize)
Base::XMLReader::XMLReader(const char* FileName, std::istream& str)
: DocumentSchema(0), ProgramVersion(""), FileVersion(0), Level(0),
CharacterOffset(-1), ReadType(None), _File(name), _valid(false),
_verbose(true),_reader(new Base::Reader(str,name)), _ownReader(true)
CharacterCount(0), ReadType(None), _File(FileName), _valid(false),
_verbose(true)
{
init(bufsize);
}
void Base::XMLReader::init(std::size_t bufsize) {
#ifdef _MSC_VER
_reader->imbue(std::locale::empty());
str.imbue(std::locale::empty());
#else
_reader->imbue(std::locale::classic());
str.imbue(std::locale::classic());
#endif
// create the parser
@@ -127,16 +74,12 @@ void Base::XMLReader::init(std::size_t bufsize) {
//parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
//parser->setFeature(XMLUni::fgXercesDynamic, true);
parser->setInputBufferSize(bufsize);
parser->setContentHandler(this);
// We don't seem to need this?
// parser->setLexicalHandler(this);
parser->setLexicalHandler(this);
parser->setErrorHandler(this);
try {
StdInputSource file(*_reader, _File.filePath().c_str());
StdInputSource file(str, _File.filePath().c_str());
_valid = parser->parseFirst(file, token);
}
catch (const XMLException& toCatch) {
@@ -162,8 +105,6 @@ Base::XMLReader::~XMLReader()
{
// Delete the parser itself. Must be done prior to calling Terminate, below.
delete parser;
if(_ownReader)
delete _reader;
}
const char* Base::XMLReader::localName() const
@@ -176,32 +117,63 @@ unsigned int Base::XMLReader::getAttributeCount() const
return static_cast<unsigned int>(AttrMap.size());
}
long Base::XMLReader::getAttributeAsInteger(const char* AttrName, const char *def) const
long Base::XMLReader::getAttributeAsInteger(const char* AttrName) const
{
return atol(getAttribute(AttrName,def));
AttrMapType::const_iterator pos = AttrMap.find(AttrName);
if (pos != AttrMap.end()) {
return atol(pos->second.c_str());
}
else {
// wrong name, use hasAttribute if not sure!
std::ostringstream msg;
msg << "XML Attribute: \"" << AttrName << "\" not found";
throw Base::XMLAttributeError(msg.str());
}
}
unsigned long Base::XMLReader::getAttributeAsUnsigned(const char* AttrName, const char *def) const
unsigned long Base::XMLReader::getAttributeAsUnsigned(const char* AttrName) const
{
return strtoul(getAttribute(AttrName,def),0,10);
AttrMapType::const_iterator pos = AttrMap.find(AttrName);
if (pos != AttrMap.end()) {
return strtoul(pos->second.c_str(),nullptr,10);
}
else {
// wrong name, use hasAttribute if not sure!
std::ostringstream msg;
msg << "XML Attribute: \"" << AttrName << "\" not found";
throw Base::XMLAttributeError(msg.str());
}
}
double Base::XMLReader::getAttributeAsFloat (const char* AttrName, const char *def) const
double Base::XMLReader::getAttributeAsFloat (const char* AttrName) const
{
return atof(getAttribute(AttrName,def));
AttrMapType::const_iterator pos = AttrMap.find(AttrName);
if (pos != AttrMap.end()) {
return atof(pos->second.c_str());
}
else {
// wrong name, use hasAttribute if not sure!
std::ostringstream msg;
msg << "XML Attribute: \"" << AttrName << "\" not found";
throw Base::XMLAttributeError(msg.str());
}
}
const char* Base::XMLReader::getAttribute (const char* AttrName, const char *def) const
const char* Base::XMLReader::getAttribute (const char* AttrName) const
{
AttrMapType::const_iterator pos = AttrMap.find(AttrName);
if (pos != AttrMap.end()) {
return pos->second.c_str();
}
else if(def)
return def;
else {
_FC_READER_THROW(Base::XMLAttributeError, "XML Attribute: '" << AttrName << "' not found");
// wrong name, use hasAttribute if not sure!
std::ostringstream msg;
msg << "XML Attribute: \"" << AttrName << "\" not found";
throw Base::XMLAttributeError(msg.str());
}
}
@@ -212,9 +184,6 @@ bool Base::XMLReader::hasAttribute (const char* AttrName) const
bool Base::XMLReader::read()
{
if(ReadType == EndDocument)
FC_READER_THROW("End of document reached");
ReadType = None;
try {
@@ -231,7 +200,7 @@ bool Base::XMLReader::read()
char* message = XMLString::transcode(toCatch.getMessage());
std::string what = message;
XMLString::release(&message);
_FC_READER_THROW(Base::XMLBaseException, what);
throw Base::XMLBaseException(what);
#endif
}
catch (const SAXParseException& toCatch) {
@@ -245,7 +214,7 @@ bool Base::XMLReader::read()
char* message = XMLString::transcode(toCatch.getMessage());
std::string what = message;
XMLString::release(&message);
FC_READER_THROW(what);
throw Base::XMLParseException(what);
#endif
}
catch (...) {
@@ -253,200 +222,146 @@ bool Base::XMLReader::read()
cerr << "Unexpected Exception \n" ;
return false;
#else
_FC_READER_THROW(Base::XMLBaseException, "Unexpected XML exception");
throw Base::XMLBaseException("Unexpected XML exception");
#endif
}
return true;
}
void Base::XMLReader::readElement(const char* ElementName, int *guard)
void Base::XMLReader::readElement(const char* ElementName)
{
endCharStream();
AttrMap.clear();
bool ok;
int currentLevel = Level;
std::string currentName = LocalName;
do {
read();
ok = read(); if (!ok) break;
if (ReadType == EndElement && currentName == LocalName && currentLevel >= Level) {
// we have reached the end of the element when calling this method
// thus we must stop reading on.
if(ElementName && currentName!=ElementName) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
// Missing element. Consider this as non-fatal
FC_WARN("Document XML element '" << (ElementName?ElementName:"") << "' not found\n"
<< "In context: " << _ReaderContext);
}
}
break;
}
else if (ReadType == EndDocument) {
// the end of the document has been reached but we still try to continue on reading
FC_READER_THROW("End of document reached");
throw Base::XMLParseException("End of document reached");
}
if(Guards.size() && Level < *Guards.back())
FC_READER_THROW("Document parsing error");
} while ((ReadType != StartElement && ReadType != StartEndElement) ||
(ElementName && LocalName != ElementName));
if(guard) {
if(ReadType == StartEndElement)
*guard = Level;
else
*guard = Level-1;
Guards.push_back(guard);
}
}
int Base::XMLReader::level() const {
return Level;
}
void Base::XMLReader::readEndElement(const char* ElementName, int *guard)
void Base::XMLReader::readEndElement(const char* ElementName, int level)
{
endCharStream();
int level = -1;
if(guard) {
level = *guard;
if(Guards.empty() || Guards.back()!=guard || Level < level)
FC_READER_THROW("Parsing error while reading end element '"
<< (ElementName?ElementName:"?") << "'");
}
// if we are already at the end of the current element
if ((ReadType == EndElement || ReadType == StartEndElement)
if (ReadType == EndElement
&& ElementName
&& LocalName == ElementName
&& (level<0 || level==Level))
{
if(guard)
Guards.pop_back();
return;
}
else if (ReadType == EndDocument) {
// the end of the document has been reached but we still try to continue on reading
FC_READER_THROW("End of document reached while reading end element '"
<< (ElementName?ElementName:"?") << "'");
throw Base::XMLParseException("End of document reached");
}
bool ok;
do {
read();
ok = read(); if (!ok) break;
if (ReadType == EndDocument)
break;
} while (ReadType != EndElement
|| (ElementName
&& (LocalName != ElementName
|| (level>=0 && level!=Level))));
if(guard)
Guards.pop_back();
}
std::streamsize Base::XMLReader::read(char_type* s, std::streamsize n) {
char_type *buf = s;
if(CharacterOffset<0)
return -1;
for(;;) {
std::streamsize copy_size = Characters.size()-CharacterOffset;
if(n<copy_size)
copy_size = n;
std::memcpy(s,Characters.c_str()+CharacterOffset,copy_size);
n -= copy_size;
s += copy_size;
CharacterOffset += copy_size;
if(!n)
break;
if(ReadType==Chars)
read();
else {
CharacterOffset = -1;
break;
}
}
return s - buf;
void Base::XMLReader::readCharacters()
{
}
void Base::XMLReader::endCharStream() {
CharacterOffset = -1;
CharStream.reset();
}
std::istream &Base::XMLReader::charStream() {
if(!CharStream)
FC_READER_THROW("no current character stream");
return *CharStream;
}
std::istream &Base::XMLReader::beginCharStream(bool base64) {
if(CharStream)
FC_READER_THROW("recursive character stream");
// TODO: An XML element can actually contain a mix of child elements and
// characters. So we should not actually demand 'StartElement' here. But
// with the current implementation of character stream, we cannot track
// child elements and character content at the same time.
if (ReadType == StartElement) {
CharacterOffset = 0;
read();
} else if (ReadType == StartEndElement) {
// If we are current at a self closing element, just leave the offset
// as negative and do not read any characters. This will result in an
// empty input stream for the caller.
CharacterOffset = -1;
} else
FC_READER_THROW("invalid state while reading character stream");
CharStream.reset(new bio::filtering_istream);
auto f = static_cast<bio::filtering_istream*>(CharStream.get());
if(base64)
f->push(base64_decoder(80,false));
f->push(boost::ref(*this));
return *CharStream;
}
void Base::XMLReader::readCharacters(const char* filename, bool base64)
void Base::XMLReader::readBinFile(const char* filename)
{
Base::FileInfo fi(filename);
Base::ofstream to(fi, std::ios::out | std::ios::binary | std::ios::trunc);
Base::ofstream to(fi, std::ios::out | std::ios::binary);
if (!to)
_FC_READER_THROW(Base::FileException, "failed to open binary file " << filename);
throw Base::FileException("XMLReader::readBinFile() Could not open file!");
beginCharStream(base64) >> to.rdbuf();
bool ok;
do {
ok = read(); if (!ok) break;
} while (ReadType != EndCDATA);
to << Base::base64_decode(Characters);
to.close();
endCharStream();
}
std::string Base::XMLReader::readCharacters()
void Base::XMLReader::readFiles(zipios::ZipInputStream &zipstream) const
{
std::stringstream ss;
beginCharStream(false) >> ss.rdbuf();
endCharStream();
return ss.str();
}
// It's possible that not all objects inside the document could be created, e.g. if a module
// is missing that would know these object types. So, there may be data files inside the zip
// file that cannot be read. We simply ignore these files.
// On the other hand, however, it could happen that a file should be read that is not part of
// the zip file. This happens e.g. if a document is written without GUI up but is read with GUI
// up. In this case the associated GUI document asks for its file which is not part of the ZIP
// file, then.
// In either case it's guaranteed that the order of the files is kept.
zipios::ConstEntryPointer entry;
try {
entry = zipstream.getNextEntry();
}
catch (const std::exception&) {
// There is no further file at all. This can happen if the
// project file was created without GUI
return;
}
std::vector<FileEntry>::const_iterator it = FileList.begin();
Base::SequencerLauncher seq("Importing project files...", FileList.size());
while (entry->isValid() && it != FileList.end()) {
std::vector<FileEntry>::const_iterator jt = it;
// Check if the current entry is registered, otherwise check the next registered files as soon as
// both file names match
while (jt != FileList.end() && entry->getName() != jt->FileName)
++jt;
// If this condition is true both file names match and we can read-in the data, otherwise
// no file name for the current entry in the zip was registered.
if (jt != FileList.end()) {
try {
Base::Reader reader(zipstream, jt->FileName, FileVersion);
jt->Object->RestoreDocFile(reader);
if (reader.getLocalReader())
reader.getLocalReader()->readFiles(zipstream);
}
catch(...) {
// For any exception we just continue with the next file.
// It doesn't matter if the last reader has read more or
// less data than the file size would allow.
// All what we need to do is to notify the user about the
// failure.
Base::Console().Error("Reading failed from embedded file: %s\n", entry->toString().c_str());
}
// Go to the next registered file name
it = jt + 1;
}
void Base::XMLReader::readFiles()
{
if(FileList.size()) {
assert(!_reader->getParent());
_reader->readFiles(*this);
seq.next();
// In either case we must go to the next entry
try {
entry = zipstream.getNextEntry();
}
catch (const std::exception&) {
// there is no further entry
break;
}
}
}
const char *Base::XMLReader::addFile(const char* Name, Base::Persistence *Object)
{
if(_reader->getParent())
return _reader->getParent()->addFile(Name,Object);
FileEntry temp;
temp.FileName = Name;
temp.Object = Object;
@@ -459,21 +374,11 @@ const char *Base::XMLReader::addFile(const char* Name, Base::Persistence *Object
const std::vector<std::string>& Base::XMLReader::getFilenames() const
{
if(_reader->getParent())
return _reader->getParent()->getFilenames();
return FileNames;
}
const std::vector<Base::XMLReader::FileEntry> &Base::XMLReader::getFileList() const {
return FileList;
}
bool Base::XMLReader::isRegistered(Base::Persistence *Object) const
{
if(_reader->getParent())
return _reader->getParent()->isRegistered(Object);
if (Object) {
for (std::vector<FileEntry>::const_iterator it = FileList.begin(); it != FileList.end(); ++it) {
if (it->Object == Object)
@@ -484,26 +389,18 @@ bool Base::XMLReader::isRegistered(Base::Persistence *Object) const
return false;
}
void Base::XMLReader::addName(const char *key, const char *value)
void Base::XMLReader::addName(const char*, const char*)
{
if(_reader->getParent())
_reader->getParent()->addName(key,value);
}
const char* Base::XMLReader::getName(const char* name) const
{
if(_reader->getParent())
return _reader->getParent()->getName(name);
else
return name;
return name;
}
bool Base::XMLReader::doNameMapping() const
{
if(_reader->getParent())
return _reader->getParent()->doNameMapping();
else
return false;
return false;
}
// ---------------------------------------------------------------------------
@@ -542,9 +439,6 @@ void Base::XMLReader::endElement (const XMLCh* const /*uri*/, const XMLCh *cons
ReadType = StartEndElement;
else
ReadType = EndElement;
if(Guards.size() && Level<*Guards.back())
*Guards.back() = INT_MAX;
}
void Base::XMLReader::startCDATA ()
@@ -558,19 +452,14 @@ void Base::XMLReader::endCDATA ()
}
#if (XERCES_VERSION_MAJOR == 2)
void Base::XMLReader::characters(const XMLCh* const chars, const unsigned int len)
void Base::XMLReader::characters(const XMLCh* const chars, const unsigned int length)
#else
void Base::XMLReader::characters(const XMLCh* const chars, const XMLSize_t len)
void Base::XMLReader::characters(const XMLCh* const chars, const XMLSize_t length)
#endif
{
(void)len;
Characters = StrX(chars).c_str();
ReadType = Chars;
// We only capture characters when some one wants it
if(CharacterOffset>=0) {
Characters = StrXUTF8(chars).c_str();
CharacterOffset = 0;
}
CharacterCount += length;
}
#if (XERCES_VERSION_MAJOR == 2)
@@ -635,11 +524,7 @@ bool Base::XMLReader::testStatus(ReaderStatus pos) const
void Base::XMLReader::setStatus(ReaderStatus pos, bool on)
{
if(testStatus(pos)!=on) {
if(_reader->getParent() && pos == PartialRestore)
_reader->getParent()->setStatus(pos,on);
StatusBits.set((size_t)pos, on);
}
StatusBits.set(static_cast<size_t>(pos), on);
}
void Base::XMLReader::setPartialRestore(bool on)
@@ -670,152 +555,32 @@ void Base::XMLReader::clearPartialRestoreObject()
// ----------------------------------------------------------
Base::Reader::Reader(std::istream &str, const std::string& name, Base::XMLReader *parent)
: std::istream(str.rdbuf()), _name(name), _parent(parent)
Base::Reader::Reader(std::istream& str, const std::string& name, int version)
: std::istream(str.rdbuf()), _str(str), _name(name), fileVersion(version)
{
}
Base::Reader::Reader(const std::string& name, Base::XMLReader *parent)
: std::istream(nullptr), _name(name), _parent(parent)
{
}
const std::string &Base::Reader::getFileName() const
std::string Base::Reader::getFileName() const
{
return this->_name;
}
int Base::Reader::getFileVersion() const
{
return _parent?_parent->FileVersion:0;
return fileVersion;
}
int Base::Reader::getDocumentSchema() const
std::istream& Base::Reader::getStream()
{
return _parent?_parent->DocumentSchema:0;
return this->_str;
}
Base::XMLReader *Base::Reader::getParent() const {
return _parent;
}
// ----------------------------------------------------------
Base::ZipReader::ZipReader(zipios::ZipInputStream &str, const std::string &name, Base::XMLReader *parent)
:Base::Reader(str,name,parent),_stream(str)
void Base::Reader::initLocalReader(std::shared_ptr<Base::XMLReader> reader)
{
this->localreader = reader;
}
void Base::ZipReader::readFiles(XMLReader &xmlReader)
std::shared_ptr<Base::XMLReader> Base::Reader::getLocalReader() const
{
// It's possible that not all objects inside the document could be created, e.g. if a module
// is missing that would know these object types. So, there may be data files inside the zip
// file that cannot be read. We simply ignore these files.
// On the other hand, however, it could happen that a file should be read that is not part of
// the zip file. This happens e.g. if a document is written without GUI up but is read with GUI
// up. In this case the associated GUI document asks for its file which is not part of the ZIP
// file, then.
// In either case it's guaranteed that the order of the files is kept.
zipios::ConstEntryPointer entry;
try {
entry = _stream.getNextEntry();
}
catch (const std::exception&) {
// There is no further file at all. This can happen if the
// project file was created without GUI
return;
}
const auto &FileList = xmlReader.getFileList();
std::size_t it = 0;
Base::SequencerLauncher seq("Importing project files...", FileList.size());
while (entry->isValid() && it < FileList.size()) {
auto jt = it;
// Check if the current entry is registered, otherwise check the next registered files as soon as
// both file names match
while (jt < FileList.size() && entry->getName() != FileList[jt].FileName)
++jt;
// If this condition is true both file names match and we can read-in the data, otherwise
// no file name for the current entry in the zip was registered.
if (jt < FileList.size()) {
try {
Base::ZipReader zipreader(_stream, FileList[jt].FileName, &xmlReader);
FileList[jt].Object->RestoreDocFile(zipreader);
} catch(Base::AbortException &e) {
e.ReportException();
FC_ERR("User abort when reading embedded file: " << FileList[jt].FileName);
throw;
} catch(Base::Exception &e) {
e.ReportException();
FC_ERR("Reading failed from embedded file: " << FileList[jt].FileName);
} catch(...) {
// For any exception we just continue with the next file.
// It doesn't matter if the last reader has read more or
// less data than the file size would allow.
// All what we need to do is to notify the user about the
// failure.
FC_ERR("Reading failed from embedded file: " << FileList[jt].FileName);
}
// Go to the next registered file name
it = jt + 1;
}
seq.next();
// In either case we must go to the next entry
try {
entry = _stream.getNextEntry();
}
catch (const std::exception&) {
// there is no further entry
break;
}
}
}
// ----------------------------------------------------------
Base::FileReader::FileReader(const Base::FileInfo &fi,
const std::string &name, Base::XMLReader *parent)
:Base::Reader(name.size()?name:fi.fileName(),parent)
,_dir(fi.dirPath())
,_stream(fi,std::ios::in|std::ios::binary)
{
this->rdbuf(_stream.rdbuf());
}
void Base::FileReader::readFiles(Base::XMLReader &xmlReader) {
const auto &FileList = xmlReader.getFileList();
Base::SequencerLauncher seq("Importing project files...", FileList.size());
std::string dirname = Base::FileInfo(_dir).fileName();
for(size_t i=0; i<FileList.size(); ++i) {
const auto &entry = FileList[i];
Base::FileInfo fi(_dir+'/'+entry.FileName);
try {
Base::FileReader freader(fi, dirname+'/'+entry.FileName, &xmlReader);
if(!freader._stream.is_open()) {
std::string msg("Failed to open ");
msg += fi.filePath();
FC_ERR(msg);
entry.Object->SetRestoreError(msg.c_str());
} else
entry.Object->RestoreDocFile(freader);
} catch(Base::AbortException &e) {
e.ReportException();
FC_ERR("User abort when reading: " << fi.filePath());
throw;
} catch(Base::Exception &e) {
e.ReportException();
FC_ERR("Reading failed: " << fi.filePath());
}
catch(...) {
// For any exception we just continue with the next file.
// It doesn't matter if the last reader has read more or
// less data than the file size would allow.
// All what we need to do is to notify the user about the
// failure.
FC_ERR("Reading failed: " << fi.filePath());
}
seq.next();
}
return(this->localreader);
}
+41 -155
View File
@@ -33,11 +33,8 @@
#include <xercesc/sax2/Attributes.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <boost/iostreams/concepts.hpp>
#include "FileInfo.h"
#include "Writer.h"
#include "Stream.h"
namespace zipios {
class ZipInputStream;
@@ -50,8 +47,7 @@ XERCES_CPP_NAMESPACE_END
namespace Base
{
class Reader;
class Persistence;
/** The XML reader class
* This is an important helper class for the store and retrieval system
@@ -128,17 +124,9 @@ public:
PartialRestoreInObject = 3 // Local to the object partially restored itself
};
/// open the file and read the first element
XMLReader(Base::Reader &reader, std::size_t bufsize=16*1024);
XMLReader(const char *name, std::istream &, std::size_t bufsize=16*1024);
XMLReader(const char* FileName, std::istream&);
~XMLReader();
/** @name boost iostream device interface */
//@{
typedef boost::iostreams::source_tag category;
typedef char char_type;
std::streamsize read(char_type* s, std::streamsize n);
//@}
bool isValid() const { return _valid; }
bool isVerbose() const { return _verbose; }
void setVerbose(bool on) { _verbose = on; }
@@ -149,68 +137,28 @@ public:
const char* localName() const;
/// get the current element level
int level() const;
/** read until a start element is found (\<name\>) or start-end element (\<name/\>) (with special name if given)
*
* @param ElementName: element name to look for. If NULL, then the
* parser will return when encounter any start element. If not NULL,
* then the parser will only search within the current element for
* any child element start with this name, and throw exception if
* not found.
*
* @param guard: The guard is used to protect against over reading when
* calling readEndElement(). When the guard is not given, it is possible
* for the matching readEndElement() call to acsend above the current level
* (at the time of calling readElement()) and look for end element in
* parent or sibling elements, potentially skipping elements in between
* without caller noticing. If the guard is given, it will be assigned the
* element level immediate above the found start element, and you must pass
* the same pointered integer when calling readEndElement() to disarm the
* guard. Every following call of read(End)Element() will check if the
* current level goes above the current guard, and throw exception if it
* does. The reader internally keeps a stack of guards, so you can setup
* additional guard when calling readElement() at deeper level.
*/
void readElement (const char* ElementName=0, int *guard=0);
/// read until a start element is found (\<name\>) or start-end element (\<name/\>) (with special name if given)
void readElement (const char* ElementName=nullptr);
/** read until an end element is found
*
* @param ElementName: optional end element name to look for. If given, then
* the parser will read until this name is found.
*
* @param guard: optional level guard. @sa readElement().
* @param level: optional level to look for. If given, then the parser will
* read until this level. Note that the parse only increase the level when
* finding a start element, not start-end element, and decrease the level
* after finding an end element. So, if you obtain the parser level after
* calling readElement(), you should specify a level minus one when calling
* this function. This \c level parameter is only useful if you know the
* child element may have the same name as its parent, otherwise, using \c
* ElementName is enough.
*/
void readEndElement(const char* ElementName=0, int *guard=0);
/** Read element character content and save to a file
*
* @param filename: file name to save into
* @param base64: whether to decode data with base64 before saving
*
* This function assumes you are in the middle of an element, or else
* exception will be thrown.
*/
void readCharacters(const char *filename, bool base64);
/** Read element character content as text string
*
* This function reads the entire character content of the current element
* and return it as a string. This function assumes you are in the middle
* of an element, or else exception will be thrown.
*
* For more memory efficient reading of large amount of characters,
* consider using beginCharStream().
*/
std::string readCharacters();
/** Obtain an input stream for reading characters
*
* @param base64: whether to decode data using base64
*
* @return Return a input stream for reading characters. The stream will be
* auto destroyed when you call with readElement() or readEndElement(), or
* you can end it explicitly with endCharStream().
*/
std::istream &beginCharStream(bool base64);
/// Manually end the current character stream
void endCharStream();
/// Obtain the current character stream
std::istream &charStream();
void readEndElement(const char* ElementName=nullptr, int level=-1);
/// read until characters are found
void readCharacters();
/// read binary file
void readBinFile(const char*);
//@}
/** @name Attribute handling */
@@ -220,31 +168,20 @@ public:
/// check if the read element has a special attribute
bool hasAttribute(const char* AttrName) const;
/// return the named attribute as an interer (does type checking)
long getAttributeAsInteger(const char* AttrName, const char *def=0) const;
unsigned long getAttributeAsUnsigned(const char* AttrName, const char *def=0) const;
long getAttributeAsInteger(const char* AttrName) const;
unsigned long getAttributeAsUnsigned(const char* AttrName) const;
/// return the named attribute as a double floating point (does type checking)
double getAttributeAsFloat(const char* AttrName, const char *def=0) const;
double getAttributeAsFloat(const char* AttrName) const;
/// return the named attribute as a double floating point (does type checking)
const char* getAttribute(const char* AttrName, const char *def=0) const;
const char* getAttribute(const char* AttrName) const;
//@}
/** @name additional file reading */
//@{
/// add a read request of a persistent object
const char *addFile(const char* Name, Base::Persistence *Object);
/// add a read request of a persistent object
const char *addFile(const std::string &Name, Base::Persistence *Object) {
return addFile(Name.c_str(),Object);
}
/// process the requested file writes
void readFiles();
struct FileEntry {
std::string FileName;
Base::Persistence *Object;
};
const std::vector<FileEntry> &getFileList() const;
void readFiles(zipios::ZipInputStream &zipstream) const;
/// get all registered file names
const std::vector<std::string>& getFilenames() const;
bool isRegistered(Base::Persistence *Object) const;
@@ -271,13 +208,15 @@ public:
bool testStatus(ReaderStatus pos) const;
/// set the status bits
void setStatus(ReaderStatus pos, bool on);
/// read the next element
bool read();
struct FileEntry {
std::string FileName;
Base::Persistence *Object;
};
std::vector<FileEntry> FileList;
protected:
void init(std::size_t bufsize);
/// read the next element
bool read();
// -----------------------------------------------------------------------
// Handlers for the SAX ContentHandler interface
@@ -320,10 +259,11 @@ protected:
void resetErrors();
//@}
int Level;
std::string LocalName;
std::string Characters;
std::streamsize CharacterOffset;
unsigned int CharacterCount;
std::map<std::string,std::string> AttrMap;
typedef std::map<std::string,std::string> AttrMapType;
@@ -347,80 +287,26 @@ protected:
bool _valid;
bool _verbose;
std::vector<FileEntry> FileList;
std::vector<std::string> FileNames;
std::vector<int*> Guards;
std::bitset<32> StatusBits;
std::unique_ptr<std::istream> CharStream;
Base::Reader *_reader;
bool _ownReader;
};
class BaseExport Reader : public std::istream
{
public:
Reader(std::istream&, const std::string&, XMLReader *parent=0);
XMLReader *getParent() const;
const std::string &getFileName() const;
Reader(std::istream&, const std::string&, int version);
std::istream& getStream();
std::string getFileName() const;
int getFileVersion() const;
int getDocumentSchema() const;
friend class XMLReader;
protected:
Reader(const std::string&, XMLReader *parent=0);
typedef XMLReader::FileEntry FileEntry;
virtual void readFiles(XMLReader &) {};
void initLocalReader(std::shared_ptr<Base::XMLReader>);
std::shared_ptr<Base::XMLReader> getLocalReader() const;
private:
std::istream& _str;
std::string _name;
XMLReader *_parent;
};
class BaseExport ZipReader : public Base::Reader
{
public:
ZipReader(zipios::ZipInputStream &, const std::string&, XMLReader *parent=0);
protected:
virtual void readFiles(XMLReader &reader);
zipios::ZipInputStream &_stream;
};
class BaseExport FileReader : public Base::Reader
{
public:
FileReader(const Base::FileInfo &fi, const std::string &name = std::string(), XMLReader *parent=0);
protected:
virtual void readFiles(XMLReader &reader);
std::string _dir;
Base::ifstream _stream;
};
/// Helper class for providing diagnoistic information in the process if xml parsing
class BaseExport ReaderContext {
private:
/// Private new operator to prevent heap allocation
void* operator new(size_t size);
void init(const char *name);
public:
ReaderContext(const char *name);
ReaderContext(const std::string &name);
~ReaderContext();
private:
std::size_t size;
int fileVersion;
std::shared_ptr<Base::XMLReader> localreader;
};
}
+4 -9
View File
@@ -33,15 +33,15 @@
using namespace Base;
Rotation::Rotation()
: quat{0.0,0.0,0.0,1.0}
, _axis{0.0,0.0,1.0}
, _angle{0.0}
{
quat[0]=quat[1]=quat[2]=0.0;quat[3]=1.0;
_axis.Set(0.0, 0.0, 1.0);
_angle = 0.0;
}
/** Construct a rotation by rotation axis and angle */
Rotation::Rotation(const Vector3d& axis, const double fAngle)
: Rotation()
{
// set to (0,0,1) as fallback in case the passed axis is the null vector
_axis.Set(0.0, 0.0, 1.0);
@@ -49,7 +49,6 @@ Rotation::Rotation(const Vector3d& axis, const double fAngle)
}
Rotation::Rotation(const Matrix4D& matrix)
: Rotation()
{
this->setValue(matrix);
}
@@ -59,7 +58,6 @@ Rotation::Rotation(const Matrix4D& matrix)
* where the quaternion is specified by q=w+xi+yj+zk.
*/
Rotation::Rotation(const double q[4])
: Rotation()
{
this->setValue(q);
}
@@ -69,19 +67,16 @@ Rotation::Rotation(const double q[4])
* where the quaternion is specified by q=w+xi+yj+zk.
*/
Rotation::Rotation(const double q0, const double q1, const double q2, const double q3)
: Rotation()
{
this->setValue(q0, q1, q2, q3);
}
Rotation::Rotation(const Vector3d & rotateFrom, const Vector3d & rotateTo)
: Rotation()
{
this->setValue(rotateFrom, rotateTo);
}
Rotation::Rotation(const Rotation& rot)
: Rotation()
{
this->quat[0] = rot.quat[0];
this->quat[1] = rot.quat[1];
+151 -3
View File
@@ -94,9 +94,135 @@
// If VC7 and later, then use the shipped 'dbghelp.h'-file
#pragma pack(push,8)
#if _MSC_VER >= 1300
#include <DbgHelp.h>
#else
// inline the important dbghelp.h-declarations...
typedef enum {
SymNone = 0,
SymCoff,
SymCv,
SymPdb,
SymExport,
SymDeferred,
SymSym,
SymDia,
SymVirtual,
NumSymTypes
} SYM_TYPE;
typedef struct _IMAGEHLP_LINE64 {
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)
PVOID Key; // internal
DWORD LineNumber; // line number in file
PCHAR FileName; // full filename
DWORD64 Address; // first instruction of line
} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
typedef struct _IMAGEHLP_MODULE64 {
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
DWORD64 BaseOfImage; // base load address of module
DWORD ImageSize; // virtual size of the loaded module
DWORD TimeDateStamp; // date/time stamp from pe header
DWORD CheckSum; // checksum from the pe header
DWORD NumSyms; // number of symbols in the symbol table
SYM_TYPE SymType; // type of symbols loaded
CHAR ModuleName[32]; // module name
CHAR ImageName[256]; // image name
CHAR LoadedImageName[256]; // symbol file name
} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
typedef struct _IMAGEHLP_SYMBOL64 {
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64)
DWORD64 Address; // virtual address including dll base address
DWORD Size; // estimated size of symbol, can be zero
DWORD Flags; // info about the symbols, see the SYMF defines
DWORD MaxNameLength; // maximum size of symbol name in 'Name'
CHAR Name[1]; // symbol name (null terminated string)
} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
typedef enum {
AddrMode1616,
AddrMode1632,
AddrModeReal,
AddrModeFlat
} ADDRESS_MODE;
typedef struct _tagADDRESS64 {
DWORD64 Offset;
WORD Segment;
ADDRESS_MODE Mode;
} ADDRESS64, *LPADDRESS64;
typedef struct _KDHELP64 {
DWORD64 Thread;
DWORD ThCallbackStack;
DWORD ThCallbackBStore;
DWORD NextCallback;
DWORD FramePointer;
DWORD64 KiCallUserMode;
DWORD64 KeUserCallbackDispatcher;
DWORD64 SystemRangeStart;
DWORD64 Reserved[8];
} KDHELP64, *PKDHELP64;
typedef struct _tagSTACKFRAME64 {
ADDRESS64 AddrPC; // program counter
ADDRESS64 AddrReturn; // return address
ADDRESS64 AddrFrame; // frame pointer
ADDRESS64 AddrStack; // stack pointer
ADDRESS64 AddrBStore; // backing store pointer
PVOID FuncTableEntry; // pointer to pdata/fpo or NULL
DWORD64 Params[4]; // possible arguments to the function
BOOL Far; // WOW far call
BOOL Virtual; // is this a virtual frame?
DWORD64 Reserved[3];
KDHELP64 KdHelp;
} STACKFRAME64, *LPSTACKFRAME64;
typedef
BOOL
(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
);
typedef
PVOID
(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
HANDLE hProcess,
DWORD64 AddrBase
);
typedef
DWORD64
(__stdcall *PGET_MODULE_BASE_ROUTINE64)(
HANDLE hProcess,
DWORD64 Address
);
typedef
DWORD64
(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
HANDLE hProcess,
HANDLE hThread,
LPADDRESS64 lpaddr
);
#define SYMOPT_CASE_INSENSITIVE 0x00000001
#define SYMOPT_UNDNAME 0x00000002
#define SYMOPT_DEFERRED_LOADS 0x00000004
#define SYMOPT_NO_CPP 0x00000008
#define SYMOPT_LOAD_LINES 0x00000010
#define SYMOPT_OMAP_FIND_NEAREST 0x00000020
#define SYMOPT_LOAD_ANYTHING 0x00000040
#define SYMOPT_IGNORE_CVREC 0x00000080
#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
#define SYMOPT_EXACT_SYMBOLS 0x00000400
#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
#define SYMOPT_PUBLICS_ONLY 0x00004000
#define SYMOPT_NO_PUBLICS 0x00008000
#define SYMOPT_AUTO_PUBLICS 0x00010000
#define SYMOPT_NO_IMAGE_SEARCH 0x00020000
#define SYMOPT_SECURE 0x00040000
#define SYMOPT_DEBUG 0x80000000
#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration
#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration;
#endif // _MSC_VER < 1300
#pragma pack(pop)
// Some missing defines (for VC5/6):
@@ -105,6 +231,15 @@
#endif
// secure-CRT_functions are only available starting with VC8
#if _MSC_VER < 1400
#define strcpy_s(dst, len, src) strcpy(dst, src)
#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
#define strcat_s(dst, len, src) strcat(dst, src)
#define _snprintf_s _snprintf
#define _tcscat_s _tcscat
#endif
static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
{
if (nMaxDestSize <= 0)
@@ -1107,7 +1242,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro
cleanup:
if (pSym) free( pSym );
if (!bLastEntryCalled)
if (bLastEntryCalled == false)
this->OnCallstackEntry(lastEntry, csEntry);
if (context == NULL)
@@ -1192,6 +1327,18 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
OnOutput(buffer);
// Also display the OS-version
#if _MSC_VER <= 1200
OSVERSIONINFOA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
ver.dwOSVersionInfoSize = sizeof(ver);
if (GetVersionExA(&ver) != FALSE)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion);
OnOutput(buffer);
}
#else
OSVERSIONINFOEXA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
ver.dwOSVersionInfoSize = sizeof(ver);
@@ -1202,6 +1349,7 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser
ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
OnOutput(buffer);
}
#endif
}
void StackWalker::OnOutput(LPCSTR buffer)

Some files were not shown because too many files have changed in this diff Show More